diff options
525 files changed, 6752 insertions, 3062 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5410613548c..ceda348025e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -389,26 +389,26 @@ jobs: os: windows-latest-xl - name: i686-mingw-1 env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu" + RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain" SCRIPT: make ci-mingw-subset-1 CUSTOM_MINGW: 1 os: windows-latest-xl - name: i686-mingw-2 env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu" + RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --set llvm.allow-old-toolchain" SCRIPT: make ci-mingw-subset-2 CUSTOM_MINGW: 1 os: windows-latest-xl - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-subset-1 - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain" CUSTOM_MINGW: 1 os: windows-latest-xl - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-subset-2 - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-profiler --set llvm.allow-old-toolchain" CUSTOM_MINGW: 1 os: windows-latest-xl - name: dist-x86_64-msvc @@ -432,7 +432,7 @@ jobs: os: windows-latest-xl - name: dist-i686-mingw env: - RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler" + RUST_CONFIGURE_ARGS: "--build=i686-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain" SCRIPT: python x.py dist CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 @@ -440,7 +440,7 @@ jobs: - name: dist-x86_64-mingw env: SCRIPT: python x.py dist - RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler" + RUST_CONFIGURE_ARGS: "--build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler --set llvm.allow-old-toolchain" CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 os: windows-latest-xl diff --git a/.gitmodules b/.gitmodules index cca60e337d2..9a664b65098 100644 --- a/.gitmodules +++ b/.gitmodules @@ -34,7 +34,7 @@ [submodule "src/llvm-project"] path = src/llvm-project url = https://github.com/rust-lang/llvm-project.git - branch = rustc/14.0-2022-06-20 + branch = rustc/15.0-2022-08-09 [submodule "src/doc/embedded-book"] path = src/doc/embedded-book url = https://github.com/rust-embedded/book.git diff --git a/Cargo.lock b/Cargo.lock index ededa7c2ecf..10ebff84887 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -333,7 +333,6 @@ dependencies = [ "cargo-util", "clap", "crates-io", - "crossbeam-utils", "curl", "curl-sys", "env_logger 0.9.0", @@ -357,7 +356,6 @@ dependencies = [ "libgit2-sys", "log", "memchr", - "num_cpus", "opener", "openssl", "os_info", @@ -417,6 +415,7 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ + "cargo_metadata 0.15.0", "directories", "rustc-workspace-hack", "rustc_version", @@ -465,6 +464,7 @@ dependencies = [ "termcolor", "toml_edit", "url 2.2.2", + "winapi", ] [[package]] @@ -659,7 +659,7 @@ dependencies = [ [[package]] name = "clippy" -version = "0.1.64" +version = "0.1.65" dependencies = [ "clippy_lints", "clippy_utils", @@ -702,7 +702,7 @@ dependencies = [ [[package]] name = "clippy_lints" -version = "0.1.64" +version = "0.1.65" dependencies = [ "cargo_metadata 0.14.0", "clippy_utils", @@ -724,7 +724,7 @@ dependencies = [ [[package]] name = "clippy_utils" -version = "0.1.64" +version = "0.1.65" dependencies = [ "arrayvec", "if_chain", @@ -816,6 +816,7 @@ dependencies = [ "getopts", "glob", "lazy_static", + "lazycell", "libc", "miow", "regex", @@ -2139,9 +2140,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.126" +version = "0.2.129" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" +checksum = "64de3cc433455c14174d42e554d4027ee631c4d046d43e3ecc6efc4636cdc7a7" dependencies = [ "rustc-std-workspace-core", ] @@ -2655,9 +2656,9 @@ checksum = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024" [[package]] name = "os_info" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eca3ecae1481e12c3d9379ec541b238a16f0b75c9a409942daa8ec20dbfdb62" +checksum = "5209b2162b2c140df493a93689e04f8deab3a67634f5bc7a553c0a98e5b8d399" dependencies = [ "log", "serde", diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index a5f1cbc96da..6529f11100d 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -19,7 +19,6 @@ #![feature(rustc_attrs)] #![cfg_attr(test, feature(test))] #![feature(strict_provenance)] -#![feature(ptr_const_cast)] use smallvec::SmallVec; diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 870a7c0be33..3f71fce0e3b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1338,14 +1338,13 @@ pub enum ExprKind { /// /// The `PathSegment` represents the method name and its generic arguments /// (within the angle brackets). - /// The first element of the vector of an `Expr` is the expression that evaluates - /// to the object on which the method is being called on (the receiver), - /// and the remaining elements are the rest of the arguments. - /// Thus, `x.foo::<Bar, Baz>(a, b, c, d)` is represented as - /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, [x, a, b, c, d])`. + /// The standalone `Expr` is the receiver expression. + /// The vector of `Expr` is the arguments. + /// `x.foo::<Bar, Baz>(a, b, c, d)` is represented as + /// `ExprKind::MethodCall(PathSegment { foo, [Bar, Baz] }, x, [a, b, c, d])`. /// This `Span` is the span of the function, without the dot and receiver /// (e.g. `foo(a, b)` in `x.foo(a, b)` - MethodCall(PathSegment, Vec<P<Expr>>, Span), + MethodCall(PathSegment, P<Expr>, Vec<P<Expr>>, Span), /// A tuple (e.g., `(a, b, c, d)`). Tup(Vec<P<Expr>>), /// A binary operation (e.g., `a + b`, `a * b`). @@ -2602,7 +2601,7 @@ pub struct Visibility { #[derive(Clone, Encodable, Decodable, Debug)] pub enum VisibilityKind { Public, - Restricted { path: P<Path>, id: NodeId }, + Restricted { path: P<Path>, id: NodeId, shorthand: bool }, Inherited, } @@ -3030,22 +3029,25 @@ pub type ForeignItem = Item<ForeignItemKind>; #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] mod size_asserts { use super::*; + use rustc_data_structures::static_assert_size; // These are in alphabetical order, which is easy to maintain. - rustc_data_structures::static_assert_size!(AssocItemKind, 72); - rustc_data_structures::static_assert_size!(Attribute, 152); - rustc_data_structures::static_assert_size!(Block, 48); - rustc_data_structures::static_assert_size!(Expr, 104); - rustc_data_structures::static_assert_size!(Fn, 192); - rustc_data_structures::static_assert_size!(ForeignItemKind, 72); - rustc_data_structures::static_assert_size!(GenericBound, 88); - rustc_data_structures::static_assert_size!(Generics, 72); - rustc_data_structures::static_assert_size!(Impl, 200); - rustc_data_structures::static_assert_size!(Item, 200); - rustc_data_structures::static_assert_size!(ItemKind, 112); - rustc_data_structures::static_assert_size!(Lit, 48); - rustc_data_structures::static_assert_size!(Pat, 120); - rustc_data_structures::static_assert_size!(Path, 40); - rustc_data_structures::static_assert_size!(PathSegment, 24); - rustc_data_structures::static_assert_size!(Stmt, 32); - rustc_data_structures::static_assert_size!(Ty, 96); + static_assert_size!(AssocItem, 160); + static_assert_size!(AssocItemKind, 72); + static_assert_size!(Attribute, 152); + static_assert_size!(Block, 48); + static_assert_size!(Expr, 104); + static_assert_size!(Fn, 192); + static_assert_size!(ForeignItem, 160); + static_assert_size!(ForeignItemKind, 72); + static_assert_size!(GenericBound, 88); + static_assert_size!(Generics, 72); + static_assert_size!(Impl, 200); + static_assert_size!(Item, 200); + static_assert_size!(ItemKind, 112); + static_assert_size!(Lit, 48); + static_assert_size!(Pat, 120); + static_assert_size!(Path, 40); + static_assert_size!(PathSegment, 24); + static_assert_size!(Stmt, 32); + static_assert_size!(Ty, 96); } diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 01bd498b377..40c05f43f68 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1302,10 +1302,11 @@ pub fn noop_visit_expr<T: MutVisitor>( vis.visit_expr(f); visit_exprs(args, vis); } - ExprKind::MethodCall(PathSegment { ident, id, args }, exprs, span) => { + ExprKind::MethodCall(PathSegment { ident, id, args }, receiver, exprs, span) => { vis.visit_ident(ident); vis.visit_id(id); visit_opt(args, |args| vis.visit_generic_args(args)); + vis.visit_expr(receiver); visit_exprs(exprs, vis); vis.visit_span(span); } @@ -1486,7 +1487,7 @@ pub fn noop_flat_map_stmt_kind<T: MutVisitor>( pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) { match &mut visibility.kind { VisibilityKind::Public | VisibilityKind::Inherited => {} - VisibilityKind::Restricted { path, id } => { + VisibilityKind::Restricted { path, id, shorthand: _ } => { vis.visit_path(path); vis.visit_id(id); } diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs index 74b7fe9e249..5edeb54be5f 100644 --- a/compiler/rustc_ast/src/util/parser.rs +++ b/compiler/rustc_ast/src/util/parser.rs @@ -396,9 +396,9 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool { contains_exterior_struct_lit(&x) } - ast::ExprKind::MethodCall(.., ref exprs, _) => { + ast::ExprKind::MethodCall(_, ref receiver, _, _) => { // X { y: 1 }.bar(...) - contains_exterior_struct_lit(&exprs[0]) + contains_exterior_struct_lit(&receiver) } _ => false, diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index d9594b323dd..4b485b547f4 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -168,8 +168,8 @@ pub trait Visitor<'ast>: Sized { fn visit_param_bound(&mut self, bounds: &'ast GenericBound, _ctxt: BoundKind) { walk_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { - walk_poly_trait_ref(self, t, m) + fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) { + walk_poly_trait_ref(self, t) } fn visit_variant_data(&mut self, s: &'ast VariantData) { walk_struct_def(self, s) @@ -177,14 +177,8 @@ pub trait Visitor<'ast>: Sized { fn visit_field_def(&mut self, s: &'ast FieldDef) { walk_field_def(self, s) } - fn visit_enum_def( - &mut self, - enum_definition: &'ast EnumDef, - generics: &'ast Generics, - item_id: NodeId, - _: Span, - ) { - walk_enum_def(self, enum_definition, generics, item_id) + fn visit_enum_def(&mut self, enum_definition: &'ast EnumDef) { + walk_enum_def(self, enum_definition) } fn visit_variant(&mut self, v: &'ast Variant) { walk_variant(self, v) @@ -287,11 +281,8 @@ pub fn walk_lifetime<'a, V: Visitor<'a>>(visitor: &mut V, lifetime: &'a Lifetime visitor.visit_ident(lifetime.ident); } -pub fn walk_poly_trait_ref<'a, V>( - visitor: &mut V, - trait_ref: &'a PolyTraitRef, - _: &TraitBoundModifier, -) where +pub fn walk_poly_trait_ref<'a, V>(visitor: &mut V, trait_ref: &'a PolyTraitRef) +where V: Visitor<'a>, { walk_list!(visitor, visit_generic_param, &trait_ref.bound_generic_params); @@ -334,7 +325,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { } ItemKind::Enum(ref enum_definition, ref generics) => { visitor.visit_generics(generics); - visitor.visit_enum_def(enum_definition, generics, item.id, item.span) + visitor.visit_enum_def(enum_definition) } ItemKind::Impl(box Impl { defaultness: _, @@ -377,12 +368,7 @@ pub fn walk_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a Item) { walk_list!(visitor, visit_attribute, &item.attrs); } -pub fn walk_enum_def<'a, V: Visitor<'a>>( - visitor: &mut V, - enum_definition: &'a EnumDef, - _: &'a Generics, - _: NodeId, -) { +pub fn walk_enum_def<'a, V: Visitor<'a>>(visitor: &mut V, enum_definition: &'a EnumDef) { walk_list!(visitor, visit_variant, &enum_definition.variants); } @@ -598,7 +584,7 @@ pub fn walk_foreign_item<'a, V: Visitor<'a>>(visitor: &mut V, item: &'a ForeignI pub fn walk_param_bound<'a, V: Visitor<'a>>(visitor: &mut V, bound: &'a GenericBound) { match *bound { - GenericBound::Trait(ref typ, ref modifier) => visitor.visit_poly_trait_ref(typ, modifier), + GenericBound::Trait(ref typ, ref _modifier) => visitor.visit_poly_trait_ref(typ), GenericBound::Outlives(ref lifetime) => { visitor.visit_lifetime(lifetime, LifetimeCtxt::Bound) } @@ -813,8 +799,9 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { visitor.visit_expr(callee_expression); walk_list!(visitor, visit_expr, arguments); } - ExprKind::MethodCall(ref segment, ref arguments, _span) => { + ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _span) => { visitor.visit_path_segment(expression.span, segment); + visitor.visit_expr(receiver); walk_list!(visitor, visit_expr, arguments); } ExprKind::Binary(_, ref left_expression, ref right_expression) => { @@ -935,7 +922,7 @@ pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { } pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { - if let VisibilityKind::Restricted { ref path, id } = vis.kind { + if let VisibilityKind::Restricted { ref path, id, shorthand: _ } = vis.kind { visitor.visit_path(path, id); } } diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index fb6715ff17e..92e6bc6013d 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -62,7 +62,7 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Call(f, self.lower_exprs(args)) } } - ExprKind::MethodCall(ref seg, ref args, span) => { + ExprKind::MethodCall(ref seg, ref receiver, ref args, span) => { let hir_seg = self.arena.alloc(self.lower_path_segment( e.span, seg, @@ -70,7 +70,9 @@ impl<'hir> LoweringContext<'_, 'hir> { ParenthesizedGenericArgs::Err, ImplTraitContext::Disallowed(ImplTraitPosition::Path), )); - let args = self.lower_exprs(args); + let args = self.arena.alloc_from_iter( + [&*receiver].into_iter().chain(args.iter()).map(|x| self.lower_expr_mut(x)), + ); hir::ExprKind::MethodCall(hir_seg, args, self.lower_span(span)) } ExprKind::Binary(binop, ref lhs, ref rhs) => { @@ -1534,15 +1536,13 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::MatchSource::ForLoopDesugar, )); - let attrs: Vec<_> = e.attrs.iter().map(|a| self.lower_attr(a)).collect(); - // This is effectively `{ let _result = ...; _result }`. // The construct was introduced in #21984 and is necessary to make sure that // temporaries in the `head` expression are dropped and do not leak to the // surrounding scope of the `match` since the `match` is not a terminating scope. // // Also, add the attributes to the outer returned expr node. - self.expr_drop_temps_mut(for_span, match_expr, attrs.into()) + self.expr_drop_temps_mut(for_span, match_expr, e.attrs.clone()) } /// Desugar `ExprKind::Try` from: `<expr>?` into: diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index d5af74d47fd..e08c1d063c1 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -295,14 +295,14 @@ impl<'a, 'hir> Visitor<'hir> for NodeCollector<'a, 'hir> { self.insert(lifetime.span, lifetime.hir_id, Node::Lifetime(lifetime)); } - fn visit_variant(&mut self, v: &'hir Variant<'hir>, g: &'hir Generics<'hir>, item_id: HirId) { + fn visit_variant(&mut self, v: &'hir Variant<'hir>) { self.insert(v.span, v.id, Node::Variant(v)); self.with_parent(v.id, |this| { // Register the constructor of this variant. if let Some(ctor_hir_id) = v.data.ctor_hir_id() { this.insert(v.span, ctor_hir_id, Node::Ctor(&v.data)); } - intravisit::walk_variant(this, v, g, item_id); + intravisit::walk_variant(this, v); }); } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 0562f7b88a3..38d30d0ffde 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -220,7 +220,20 @@ impl ResolverAstLoweringExt for ResolverAstLowering { } fn get_remapped_def_id(&self, mut local_def_id: LocalDefId) -> LocalDefId { - for map in &self.generics_def_id_map { + // `generics_def_id_map` is a stack of mappings. As we go deeper in impl traits nesting we + // push new mappings so we need to try first the latest mappings, hence `iter().rev()`. + // + // Consider: + // + // `fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {}` + // + // We would end with a generics_def_id_map like: + // + // `[[fn#'b -> impl_trait#'b], [fn#'b -> impl_sized#'b]]` + // + // for the opaque type generated on `impl Sized + 'b`, We want the result to be: + // impl_sized#'b, so iterating forward is the wrong thing to do. + for map in self.generics_def_id_map.iter().rev() { if let Some(r) = map.get(&local_def_id) { debug!("def_id_remapper: remapping from `{local_def_id:?}` to `{r:?}`"); local_def_id = *r; diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs index 81006e00fd4..8c67cebae55 100644 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs @@ -1,9 +1,6 @@ use super::ResolverAstLoweringExt; use rustc_ast::visit::{self, BoundKind, LifetimeCtxt, Visitor}; -use rustc_ast::{ - FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, TraitBoundModifier, Ty, - TyKind, -}; +use rustc_ast::{FnRetTy, GenericBounds, Lifetime, NodeId, PathSegment, PolyTraitRef, Ty, TyKind}; use rustc_hir::def::LifetimeRes; use rustc_middle::span_bug; use rustc_middle::ty::ResolverAstLowering; @@ -71,10 +68,10 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> { visit::walk_path_segment(self, path_span, path_segment); } - fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef, m: &'ast TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &'ast PolyTraitRef) { self.current_binders.push(t.trait_ref.ref_id); - visit::walk_poly_trait_ref(self, t, m); + visit::walk_poly_trait_ref(self, t); self.current_binders.pop(); } diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 60560b1c00e..e61dfef7bd3 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -13,9 +13,7 @@ use rustc_ast::walk_list; use rustc_ast::*; use rustc_ast_pretty::pprust::{self, State}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{ - error_code, pluralize, struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, -}; +use rustc_errors::{error_code, pluralize, struct_span_err, Applicability, Diagnostic}; use rustc_parse::validate_attr; use rustc_session::lint::builtin::{ DEPRECATED_WHERE_CLAUSE_LOCATION, MISSING_ABI, PATTERNS_IN_FNS_WITHOUT_BODY, @@ -477,7 +475,7 @@ impl<'a> AstValidator<'a> { ctx: &str, msg: &str, sugg: &str, - help: impl FnOnce(&mut DiagnosticBuilder<'_, ErrorGuaranteed>), + help: impl FnOnce(&mut Diagnostic), ) { let source_map = self.session.source_map(); let end = source_map.end_point(sp); @@ -1196,7 +1194,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { let msg = "free function without a body"; let ext = sig.header.ext; - let f = |e: &mut DiagnosticBuilder<'_, _>| { + let f = |e: &mut Diagnostic| { if let Extern::Implicit(start_span) | Extern::Explicit(_, start_span) = &ext { let start_suggestion = if let Extern::Explicit(abi, _) = ext { @@ -1538,25 +1536,17 @@ impl<'a> Visitor<'a> for AstValidator<'a> { visit::walk_param_bound(self, bound) } - fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef, m: &'a TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &'a PolyTraitRef) { self.check_late_bound_lifetime_defs(&t.bound_generic_params); - visit::walk_poly_trait_ref(self, t, m); + visit::walk_poly_trait_ref(self, t); } fn visit_variant_data(&mut self, s: &'a VariantData) { self.with_banned_assoc_ty_bound(|this| visit::walk_struct_def(this, s)) } - fn visit_enum_def( - &mut self, - enum_definition: &'a EnumDef, - generics: &'a Generics, - item_id: NodeId, - _: Span, - ) { - self.with_banned_assoc_ty_bound(|this| { - visit::walk_enum_def(this, enum_definition, generics, item_id) - }) + fn visit_enum_def(&mut self, enum_definition: &'a EnumDef) { + self.with_banned_assoc_ty_bound(|this| visit::walk_enum_def(this, enum_definition)) } fn visit_fn(&mut self, fk: FnKind<'a>, span: Span, id: NodeId) { diff --git a/compiler/rustc_ast_passes/src/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs index 9c7369c83e2..be3e46661bf 100644 --- a/compiler/rustc_ast_passes/src/node_count.rs +++ b/compiler/rustc_ast_passes/src/node_count.rs @@ -79,9 +79,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_param_bound(self, bounds) } - fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef, m: &TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, t: &PolyTraitRef) { self.count += 1; - walk_poly_trait_ref(self, t, m) + walk_poly_trait_ref(self, t) } fn visit_variant_data(&mut self, s: &VariantData) { self.count += 1; @@ -91,15 +91,9 @@ impl<'ast> Visitor<'ast> for NodeCounter { self.count += 1; walk_field_def(self, s) } - fn visit_enum_def( - &mut self, - enum_definition: &EnumDef, - generics: &Generics, - item_id: NodeId, - _: Span, - ) { + fn visit_enum_def(&mut self, enum_definition: &EnumDef) { self.count += 1; - walk_enum_def(self, enum_definition, generics, item_id) + walk_enum_def(self, enum_definition) } fn visit_variant(&mut self, v: &Variant) { self.count += 1; diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index ead38caee28..bcefa8ce0b9 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -193,9 +193,13 @@ impl<'a> State<'a> { self.print_call_post(args) } - fn print_expr_method_call(&mut self, segment: &ast::PathSegment, args: &[P<ast::Expr>]) { - let base_args = &args[1..]; - self.print_expr_maybe_paren(&args[0], parser::PREC_POSTFIX); + fn print_expr_method_call( + &mut self, + segment: &ast::PathSegment, + receiver: &ast::Expr, + base_args: &[P<ast::Expr>], + ) { + self.print_expr_maybe_paren(receiver, parser::PREC_POSTFIX); self.word("."); self.print_ident(segment.ident); if let Some(ref args) = segment.args { @@ -303,8 +307,8 @@ impl<'a> State<'a> { ast::ExprKind::Call(ref func, ref args) => { self.print_expr_call(func, &args); } - ast::ExprKind::MethodCall(ref segment, ref args, _) => { - self.print_expr_method_call(segment, &args); + ast::ExprKind::MethodCall(ref segment, ref receiver, ref args, _) => { + self.print_expr_method_call(segment, &receiver, &args); } ast::ExprKind::Binary(op, ref lhs, ref rhs) => { self.print_expr_binary(op, lhs, rhs); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index f1caf22f364..bd87987010e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -412,9 +412,9 @@ impl<'a> State<'a> { pub(crate) fn print_visibility(&mut self, vis: &ast::Visibility) { match vis.kind { ast::VisibilityKind::Public => self.word_nbsp("pub"), - ast::VisibilityKind::Restricted { ref path, .. } => { + ast::VisibilityKind::Restricted { ref path, id: _, shorthand } => { let path = Self::to_string(|s| s.print_path(path, false, 0)); - if path == "crate" || path == "self" || path == "super" { + if shorthand && (path == "crate" || path == "self" || path == "super") { self.word_nbsp(format!("pub({})", path)) } else { self.word_nbsp(format!("pub(in {})", path)) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 8bc8964bbd7..84a0d4ba7ba 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -451,7 +451,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn suggest_borrow_fn_like( &self, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut Diagnostic, ty: Ty<'tcx>, move_sites: &[MoveSite], value_name: &str, @@ -526,12 +526,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { true } - fn suggest_adding_copy_bounds( - &self, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, - ty: Ty<'tcx>, - span: Span, - ) { + fn suggest_adding_copy_bounds(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) { let tcx = self.infcx.tcx; let generics = tcx.generics_of(self.mir_def_id()); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 176090c3b7a..bd3a2a3d694 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -783,7 +783,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { fn maybe_suggest_constrain_dyn_trait_impl( &self, - diag: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + diag: &mut Diagnostic, f: Region<'tcx>, o: Region<'tcx>, category: &ConstraintCategory<'tcx>, diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index 16796091830..9fab7ad914a 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::region_constraints::{GenericKind, VerifyBound}; use rustc_infer::infer::{self, InferCtxt, SubregionOrigin}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::TypeVisitable; +use rustc_middle::ty::TypeFoldable; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{Span, DUMMY_SP}; @@ -109,23 +109,11 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { self.add_outlives(r1_vid, r2_vid); } - GenericArgKind::Type(mut t1) => { + GenericArgKind::Type(t1) => { // we don't actually use this for anything, but // the `TypeOutlives` code needs an origin. let origin = infer::RelateParamBound(DUMMY_SP, t1, None); - // Placeholder regions need to be converted now because it may - // create new region variables, which can't be done later when - // verifying these bounds. - if t1.has_placeholders() { - t1 = tcx.fold_regions(t1, |r, _| match *r { - ty::RePlaceholder(placeholder) => { - self.constraints.placeholder_region(self.infcx, placeholder) - } - _ => r, - }); - } - TypeOutlives::new( &mut *self, tcx, @@ -143,6 +131,25 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { } } + /// Placeholder regions need to be converted eagerly because it may + /// create new region variables, which we must not do when verifying + /// our region bounds. + /// + /// FIXME: This should get removed once higher ranked region obligations + /// are dealt with during trait solving. + fn replace_placeholders_with_nll<T: TypeFoldable<'tcx>>(&mut self, value: T) -> T { + if value.has_placeholders() { + self.tcx.fold_regions(value, |r, _| match *r { + ty::RePlaceholder(placeholder) => { + self.constraints.placeholder_region(self.infcx, placeholder) + } + _ => r, + }) + } else { + value + } + } + fn verify_to_type_test( &mut self, generic_kind: GenericKind<'tcx>, @@ -150,7 +157,6 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { verify_bound: VerifyBound<'tcx>, ) -> TypeTest<'tcx> { let lower_bound = self.to_region_vid(region); - TypeTest { generic_kind, lower_bound, locations: self.locations, verify_bound } } @@ -198,6 +204,8 @@ impl<'a, 'b, 'tcx> TypeOutlivesDelegate<'tcx> for &'a mut ConstraintConversion<' a: ty::Region<'tcx>, bound: VerifyBound<'tcx>, ) { + let kind = self.replace_placeholders_with_nll(kind); + let bound = self.replace_placeholders_with_nll(bound); let type_test = self.verify_to_type_test(kind, a, bound); self.add_type_test(type_test); } diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs index cc0318ede54..74655369faf 100644 --- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs +++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs @@ -242,10 +242,9 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { let constraint_sets: Vec<_> = unnormalized_input_output_tys .flat_map(|ty| { debug!("build: input_or_output={:?}", ty); - // We only add implied bounds for the normalized type as the unnormalized - // type may not actually get checked by the caller. - // - // Can otherwise be unsound, see #91068. + // We add implied bounds from both the unnormalized and normalized ty. + // See issue #87748 + let constraints_implied1 = self.add_implied_bounds(ty); let TypeOpOutput { output: norm_ty, constraints: constraints1, .. } = self .param_env .and(type_op::normalize::Normalize::new(ty)) @@ -273,9 +272,10 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> { // } // ``` // Both &Self::Bar and &() are WF - let constraints_implied = self.add_implied_bounds(norm_ty); + let constraints_implied2 = + if ty != norm_ty { self.add_implied_bounds(norm_ty) } else { None }; normalized_inputs_and_output.push(norm_ty); - constraints1.into_iter().chain(constraints_implied) + constraints1.into_iter().chain(constraints_implied1).chain(constraints_implied2) }) .collect(); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d32b1edcd8f..7bf7f7357bf 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1448,9 +1448,14 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { )) }); debug!(?sig); - let sig = self.normalize(sig, term_location); - self.check_call_dest(body, term, &sig, *destination, target, term_location); - + // IMPORTANT: We have to prove well formed for the function signature before + // we normalize it, as otherwise types like `<&'a &'b () as Trait>::Assoc` + // get normalized away, causing us to ignore the `'b: 'a` bound used by the function. + // + // Normalization results in a well formed type if the input is well formed, so we + // don't have to check it twice. + // + // See #91068 for an example. self.prove_predicates( sig.inputs_and_output .iter() @@ -1458,6 +1463,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { term_location.to_locations(), ConstraintCategory::Boring, ); + let sig = self.normalize(sig, term_location); + self.check_call_dest(body, term, &sig, *destination, target, term_location); // The ordinary liveness rules will ensure that all // regions in the type of the callee are live here. We diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index dcea883a5a3..c04d04020cc 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -240,8 +240,8 @@ impl<'cx, 'a> Context<'cx, 'a> { self.manage_cond_expr(prefix); self.manage_cond_expr(suffix); } - ExprKind::MethodCall(_, ref mut local_exprs, _) => { - for local_expr in local_exprs.iter_mut().skip(1) { + ExprKind::MethodCall(_, _,ref mut local_exprs, _) => { + for local_expr in local_exprs.iter_mut() { self.manage_cond_expr(local_expr); } } @@ -377,14 +377,12 @@ impl<'cx, 'a> Context<'cx, 'a> { id: DUMMY_NODE_ID, ident: Ident::new(sym::try_capture, self.span), }, - vec![ - expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)), - expr_addr_of_mut( - self.cx, - self.span, - self.cx.expr_path(Path::from_ident(capture)), - ), - ], + expr_paren(self.cx, self.span, self.cx.expr_addr_of(self.span, wrapper)), + vec![expr_addr_of_mut( + self.cx, + self.span, + self.cx.expr_path(Path::from_ident(capture)), + )], self.span, )) .add_trailing_semicolon(); @@ -442,10 +440,11 @@ fn expr_addr_of_mut(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> { fn expr_method_call( cx: &ExtCtxt<'_>, path: PathSegment, + receiver: P<Expr>, args: Vec<P<Expr>>, span: Span, ) -> P<Expr> { - cx.expr(span, ExprKind::MethodCall(path, args, span)) + cx.expr(span, ExprKind::MethodCall(path, receiver, args, span)) } fn expr_paren(cx: &ExtCtxt<'_>, sp: Span, e: P<Expr>) -> P<Expr> { diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 735017aa5a8..ef64f52d40b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -383,16 +383,12 @@ fn find_type_parameters( } // Place bound generic params on a stack, to extract them when a type is encountered. - fn visit_poly_trait_ref( - &mut self, - trait_ref: &'a ast::PolyTraitRef, - modifier: &'a ast::TraitBoundModifier, - ) { + fn visit_poly_trait_ref(&mut self, trait_ref: &'a ast::PolyTraitRef) { let stack_len = self.bound_generic_params_stack.len(); self.bound_generic_params_stack .extend(trait_ref.bound_generic_params.clone().into_iter()); - visit::walk_poly_trait_ref(self, trait_ref, modifier); + visit::walk_poly_trait_ref(self, trait_ref); self.bound_generic_params_stack.truncate(stack_len); } diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index 532049c858d..402fbb16f97 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -15,9 +15,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.56" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "c794e162a5eff65c72ef524dfe393eb923c354e350bb78b9c7383df13f3bc142" [[package]] name = "ar" diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index a0a640473eb..96d238eda59 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -440,6 +440,8 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str .features .split(',') .filter(|v| !v.is_empty() && backend_feature_name(v).is_some()) + // Drop +atomics-32 feature introduced in LLVM 15. + .filter(|v| *v != "+atomics-32" || get_version() >= (15, 0, 0)) .map(String::from), ); diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 63207803e32..953761a7820 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1583,12 +1583,21 @@ fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { fn add_pre_link_objects( cmd: &mut dyn Linker, sess: &Session, + flavor: LinkerFlavor, link_output_kind: LinkOutputKind, self_contained: bool, ) { + // FIXME: we are currently missing some infra here (per-linker-flavor CRT objects), + // so Fuchsia has to be special-cased. let opts = &sess.target; - let objects = - if self_contained { &opts.pre_link_objects_fallback } else { &opts.pre_link_objects }; + let empty = Default::default(); + let objects = if self_contained { + &opts.pre_link_objects_fallback + } else if !(sess.target.os == "fuchsia" && flavor == LinkerFlavor::Gcc) { + &opts.pre_link_objects + } else { + &empty + }; for obj in objects.get(&link_output_kind).iter().copied().flatten() { cmd.add_object(&get_object_file_path(sess, obj, self_contained)); } @@ -1914,7 +1923,7 @@ fn linker_with_args<'a>( // ------------ Object code and libraries, order-dependent ------------ // Pre-link CRT objects. - add_pre_link_objects(cmd, sess, link_output_kind, crt_objects_fallback); + add_pre_link_objects(cmd, sess, flavor, link_output_kind, crt_objects_fallback); add_linked_symbol_object( cmd, @@ -2070,7 +2079,10 @@ fn add_order_independent_options( add_link_script(cmd, sess, tmpdir, crate_type); - if sess.target.os == "fuchsia" && crate_type == CrateType::Executable { + if sess.target.os == "fuchsia" + && crate_type == CrateType::Executable + && flavor != LinkerFlavor::Gcc + { let prefix = if sess.opts.unstable_opts.sanitizer.contains(SanitizerSet::ADDRESS) { "asan/" } else { @@ -2674,11 +2686,16 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { let os = &sess.target.os; let llvm_target = &sess.target.llvm_target; if sess.target.vendor != "apple" - || !matches!(os.as_ref(), "ios" | "tvos" | "watchos") + || !matches!(os.as_ref(), "ios" | "tvos" | "watchos" | "macos") || (flavor != LinkerFlavor::Gcc && flavor != LinkerFlavor::Lld(LldFlavor::Ld64)) { return; } + + if os == "macos" && flavor != LinkerFlavor::Lld(LldFlavor::Ld64) { + return; + } + let sdk_name = match (arch.as_ref(), os.as_ref()) { ("aarch64", "tvos") => "appletvos", ("x86_64", "tvos") => "appletvsimulator", @@ -2694,6 +2711,7 @@ fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { ("aarch64", "watchos") if llvm_target.ends_with("-simulator") => "watchsimulator", ("aarch64", "watchos") => "watchos", ("arm", "watchos") => "watchos", + (_, "macos") => "macosx", _ => { sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os)); return; diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index fc2e6652a3d..684877cae76 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -236,6 +236,16 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, const PANIC_ON_ALLOC_FAIL: bool = false; // will be raised as a proper error + #[inline(always)] + fn enforce_alignment(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks + } + + #[inline(always)] + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.tcx.sess.opts.unstable_opts.extra_const_ub_checks + } + fn load_mir( ecx: &InterpCx<'mir, 'tcx, Self>, instance: ty::InstanceDef<'tcx>, diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs index 71ccd1799fa..9b9919fcc2a 100644 --- a/compiler/rustc_const_eval/src/interpret/machine.rs +++ b/compiler/rustc_const_eval/src/interpret/machine.rs @@ -437,24 +437,12 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { type FrameExtra = (); #[inline(always)] - fn enforce_alignment(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - // We do not check for alignment to avoid having to carry an `Align` - // in `ConstValue::ByRef`. - false - } - - #[inline(always)] fn force_int_for_alignment_check(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { // We do not support `force_int`. false } #[inline(always)] - fn enforce_validity(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { - false // for now, we don't enforce validity - } - - #[inline(always)] fn enforce_number_init(_ecx: &InterpCx<$mir, $tcx, Self>) -> bool { true } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index 94ba62c160c..fe80a55dfd2 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -823,9 +823,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] mod size_asserts { use super::*; + use rustc_data_structures::static_assert_size; // These are in alphabetical order, which is easy to maintain. - rustc_data_structures::static_assert_size!(Immediate, 56); - rustc_data_structures::static_assert_size!(ImmTy<'_>, 72); - rustc_data_structures::static_assert_size!(Operand, 64); - rustc_data_structures::static_assert_size!(OpTy<'_>, 88); + static_assert_size!(Immediate, 56); + static_assert_size!(ImmTy<'_>, 72); + static_assert_size!(Operand, 64); + static_assert_size!(OpTy<'_>, 88); } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index f4571a1ca3d..97fe23cb5bc 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -891,10 +891,11 @@ where #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] mod size_asserts { use super::*; + use rustc_data_structures::static_assert_size; // These are in alphabetical order, which is easy to maintain. - rustc_data_structures::static_assert_size!(MemPlaceMeta, 24); - rustc_data_structures::static_assert_size!(MemPlace, 40); - rustc_data_structures::static_assert_size!(MPlaceTy<'_>, 64); - rustc_data_structures::static_assert_size!(Place, 48); - rustc_data_structures::static_assert_size!(PlaceTy<'_>, 72); + static_assert_size!(MemPlaceMeta, 24); + static_assert_size!(MemPlace, 40); + static_assert_size!(MPlaceTy<'_>, 64); + static_assert_size!(Place, 48); + static_assert_size!(PlaceTy<'_>, 72); } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index 6f6717721fb..f1b1855c3ec 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -1005,6 +1005,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// It will error if the bits at the destination do not match the ones described by the layout. #[inline(always)] pub fn validate_operand(&self, op: &OpTy<'tcx, M::Provenance>) -> InterpResult<'tcx> { + // Note that we *could* actually be in CTFE here with `-Zextra-const-ub-checks`, but it's + // still correct to not use `ctfe_mode`: that mode is for validation of the final constant + // value, it rules out things like `UnsafeCell` in awkward places. It also can make checking + // recurse through references which, for now, we don't want here, either. self.validate_operand_internal(op, vec![], None, None) } } diff --git a/compiler/rustc_driver/src/lib.rs b/compiler/rustc_driver/src/lib.rs index 53ae913f94f..94639bf8e1e 100644 --- a/compiler/rustc_driver/src/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -1148,6 +1148,17 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + LazyLock::new(|| { let hook = panic::take_hook(); panic::set_hook(Box::new(|info| { + // If the error was caused by a broken pipe then this is not a bug. + // Write the error and return immediately. See #98700. + #[cfg(windows)] + if let Some(msg) = info.payload().downcast_ref::<String>() { + if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") + { + early_error_no_abort(ErrorOutputType::default(), &msg); + return; + } + }; + // Invoke the default handler, which prints the actual panic message and optionally a backtrace (*DEFAULT_HOOK)(info); diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 2d3155a70ed..15c1858023d 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -4,7 +4,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(drain_filter)] -#![feature(backtrace)] #![feature(if_let_guard)] #![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index f7e1575afbf..e009e4f7c68 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -14,7 +14,7 @@ use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, TransparencyError}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; -use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder}; use rustc_feature::Features; use rustc_lint_defs::builtin::{ RUST_2021_INCOMPATIBLE_OR_PATTERNS, SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, @@ -608,11 +608,7 @@ enum ExplainDocComment { }, } -fn annotate_doc_comment( - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, - sm: &SourceMap, - span: Span, -) { +fn annotate_doc_comment(err: &mut Diagnostic, sm: &SourceMap, span: Span) { if let Ok(src) = sm.span_to_snippet(span) { if src.starts_with("///") || src.starts_with("/**") { err.subdiagnostic(ExplainDocComment::Outer { span }); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 617433a9803..7a87a3e4882 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -3491,16 +3491,16 @@ impl<'hir> Node<'hir> { mod size_asserts { use super::*; // These are in alphabetical order, which is easy to maintain. - rustc_data_structures::static_assert_size!(Block<'static>, 48); - rustc_data_structures::static_assert_size!(Expr<'static>, 56); - rustc_data_structures::static_assert_size!(ForeignItem<'static>, 72); - rustc_data_structures::static_assert_size!(GenericBound<'_>, 48); - rustc_data_structures::static_assert_size!(Generics<'static>, 56); - rustc_data_structures::static_assert_size!(ImplItem<'static>, 88); - rustc_data_structures::static_assert_size!(Impl<'static>, 80); - rustc_data_structures::static_assert_size!(Item<'static>, 80); - rustc_data_structures::static_assert_size!(Pat<'static>, 88); - rustc_data_structures::static_assert_size!(QPath<'static>, 24); - rustc_data_structures::static_assert_size!(TraitItem<'static>, 96); - rustc_data_structures::static_assert_size!(Ty<'static>, 72); + static_assert_size!(Block<'static>, 48); + static_assert_size!(Expr<'static>, 56); + static_assert_size!(ForeignItem<'static>, 72); + static_assert_size!(GenericBound<'_>, 48); + static_assert_size!(Generics<'static>, 56); + static_assert_size!(ImplItem<'static>, 88); + static_assert_size!(Impl<'static>, 80); + static_assert_size!(Item<'static>, 80); + static_assert_size!(Pat<'static>, 88); + static_assert_size!(QPath<'static>, 24); + static_assert_size!(TraitItem<'static>, 96); + static_assert_size!(Ty<'static>, 72); } diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs index e676acebe35..51b1bfad8a0 100644 --- a/compiler/rustc_hir/src/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -385,30 +385,17 @@ pub trait Visitor<'v>: Sized { fn visit_poly_trait_ref(&mut self, t: &'v PolyTraitRef<'v>, m: TraitBoundModifier) { walk_poly_trait_ref(self, t, m) } - fn visit_variant_data( - &mut self, - s: &'v VariantData<'v>, - _: Symbol, - _: &'v Generics<'v>, - _parent_id: HirId, - _: Span, - ) { + fn visit_variant_data(&mut self, s: &'v VariantData<'v>) { walk_struct_def(self, s) } fn visit_field_def(&mut self, s: &'v FieldDef<'v>) { walk_field_def(self, s) } - fn visit_enum_def( - &mut self, - enum_definition: &'v EnumDef<'v>, - generics: &'v Generics<'v>, - item_id: HirId, - _: Span, - ) { - walk_enum_def(self, enum_definition, generics, item_id) + fn visit_enum_def(&mut self, enum_definition: &'v EnumDef<'v>, item_id: HirId) { + walk_enum_def(self, enum_definition, item_id) } - fn visit_variant(&mut self, v: &'v Variant<'v>, g: &'v Generics<'v>, item_id: HirId) { - walk_variant(self, v, g, item_id) + fn visit_variant(&mut self, v: &'v Variant<'v>) { + walk_variant(self, v) } fn visit_label(&mut self, label: &'v Label) { walk_label(self, label) @@ -572,7 +559,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { ItemKind::Enum(ref enum_definition, ref generics) => { visitor.visit_generics(generics); // `visit_enum_def()` takes care of visiting the `Item`'s `HirId`. - visitor.visit_enum_def(enum_definition, generics, item.hir_id(), item.span) + visitor.visit_enum_def(enum_definition, item.hir_id()) } ItemKind::Impl(Impl { unsafety: _, @@ -595,13 +582,7 @@ pub fn walk_item<'v, V: Visitor<'v>>(visitor: &mut V, item: &'v Item<'v>) { | ItemKind::Union(ref struct_definition, ref generics) => { visitor.visit_generics(generics); visitor.visit_id(item.hir_id()); - visitor.visit_variant_data( - struct_definition, - item.ident.name, - generics, - item.hir_id(), - item.span, - ); + visitor.visit_variant_data(struct_definition); } ItemKind::Trait(.., ref generics, bounds, trait_item_refs) => { visitor.visit_id(item.hir_id()); @@ -649,28 +630,16 @@ pub fn walk_use<'v, V: Visitor<'v>>(visitor: &mut V, path: &'v Path<'v>, hir_id: pub fn walk_enum_def<'v, V: Visitor<'v>>( visitor: &mut V, enum_definition: &'v EnumDef<'v>, - generics: &'v Generics<'v>, item_id: HirId, ) { visitor.visit_id(item_id); - walk_list!(visitor, visit_variant, enum_definition.variants, generics, item_id); + walk_list!(visitor, visit_variant, enum_definition.variants); } -pub fn walk_variant<'v, V: Visitor<'v>>( - visitor: &mut V, - variant: &'v Variant<'v>, - generics: &'v Generics<'v>, - parent_item_id: HirId, -) { +pub fn walk_variant<'v, V: Visitor<'v>>(visitor: &mut V, variant: &'v Variant<'v>) { visitor.visit_ident(variant.ident); visitor.visit_id(variant.id); - visitor.visit_variant_data( - &variant.data, - variant.ident.name, - generics, - parent_item_id, - variant.span, - ); + visitor.visit_variant_data(&variant.data); walk_list!(visitor, visit_anon_const, &variant.disr_expr); } diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 0d4472a1cfd..780e6ead10e 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -187,7 +187,7 @@ pub enum GenericKind<'tcx> { /// } /// ``` /// This is described with an `AnyRegion('a, 'b)` node. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, TypeFoldable, TypeVisitable)] pub enum VerifyBound<'tcx> { /// See [`VerifyIfEq`] docs IfEq(ty::Binder<'tcx, VerifyIfEq<'tcx>>), diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs index d13711c3ab5..cbf1a677555 100644 --- a/compiler/rustc_lint/src/early.rs +++ b/compiler/rustc_lint/src/early.rs @@ -233,9 +233,9 @@ impl<'a, T: EarlyLintPass> ast_visit::Visitor<'a> for EarlyContextAndPass<'a, T> ast_visit::walk_where_predicate(self, p); } - fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef, m: &'a ast::TraitBoundModifier) { - run_early_pass!(self, check_poly_trait_ref, t, m); - ast_visit::walk_poly_trait_ref(self, t, m); + fn visit_poly_trait_ref(&mut self, t: &'a ast::PolyTraitRef) { + run_early_pass!(self, check_poly_trait_ref, t); + ast_visit::walk_poly_trait_ref(self, t); } fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: ast_visit::AssocCtxt) { diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index a329b37519d..5188ac633d3 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -24,7 +24,6 @@ use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::LintPass; -use rustc_span::symbol::Symbol; use rustc_span::Span; use std::any::Any; @@ -194,14 +193,7 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas self.context.cached_typeck_results.set(old_cached_typeck_results); } - fn visit_variant_data( - &mut self, - s: &'tcx hir::VariantData<'tcx>, - _: Symbol, - _: &'tcx hir::Generics<'tcx>, - _: hir::HirId, - _: Span, - ) { + fn visit_variant_data(&mut self, s: &'tcx hir::VariantData<'tcx>) { lint_callback!(self, check_struct_def, s); hir_visit::walk_struct_def(self, s); } @@ -213,15 +205,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas }) } - fn visit_variant( - &mut self, - v: &'tcx hir::Variant<'tcx>, - g: &'tcx hir::Generics<'tcx>, - item_id: hir::HirId, - ) { + fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { self.with_lint_attrs(v.id, |cx| { lint_callback!(cx, check_variant, v); - hir_visit::walk_variant(cx, v, g, item_id); + hir_visit::walk_variant(cx, v); }) } diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 00e96f20d1a..7ab9302d835 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -772,14 +772,9 @@ impl<'tcx> intravisit::Visitor<'tcx> for LintLevelMapBuilder<'tcx> { }) } - fn visit_variant( - &mut self, - v: &'tcx hir::Variant<'tcx>, - g: &'tcx hir::Generics<'tcx>, - item_id: hir::HirId, - ) { + fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { self.with_lint_attrs(v.id, |builder| { - intravisit::walk_variant(builder, v, g, item_id); + intravisit::walk_variant(builder, v); }) } diff --git a/compiler/rustc_lint/src/passes.rs b/compiler/rustc_lint/src/passes.rs index cb7bd407ed4..413f06a97a2 100644 --- a/compiler/rustc_lint/src/passes.rs +++ b/compiler/rustc_lint/src/passes.rs @@ -156,8 +156,7 @@ macro_rules! early_lint_methods { fn check_generic_arg(a: &ast::GenericArg); fn check_generic_param(a: &ast::GenericParam); fn check_generics(a: &ast::Generics); - fn check_poly_trait_ref(a: &ast::PolyTraitRef, - b: &ast::TraitBoundModifier); + fn check_poly_trait_ref(a: &ast::PolyTraitRef); fn check_fn(a: rustc_ast::visit::FnKind<'_>, c: Span, d_: ast::NodeId); fn check_trait_item(a: &ast::AssocItem); fn check_impl_item(a: &ast::AssocItem); diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index b6cf182916c..58b2f0a4416 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -11,7 +11,7 @@ use rustc_middle::ty::adjustment; use rustc_middle::ty::{self, Ty}; use rustc_span::symbol::Symbol; use rustc_span::symbol::{kw, sym}; -use rustc_span::{BytePos, Span, DUMMY_SP}; +use rustc_span::{BytePos, Span}; declare_lint! { /// The `unused_must_use` lint detects unused result of a type flagged as @@ -504,23 +504,23 @@ trait UnusedDelimLint { ast::ExprKind::Block(ref block, None) if block.stmts.len() > 0 => { let start = block.stmts[0].span; let end = block.stmts[block.stmts.len() - 1].span; - if value.span.from_expansion() || start.from_expansion() || end.from_expansion() { - ( - value.span.with_hi(value.span.lo() + BytePos(1)), - value.span.with_lo(value.span.hi() - BytePos(1)), - ) + if let Some(start) = start.find_ancestor_inside(value.span) + && let Some(end) = end.find_ancestor_inside(value.span) + { + Some(( + value.span.with_hi(start.lo()), + value.span.with_lo(end.hi()), + )) } else { - (value.span.with_hi(start.lo()), value.span.with_lo(end.hi())) + None } } ast::ExprKind::Paren(ref expr) => { - if value.span.from_expansion() || expr.span.from_expansion() { - ( - value.span.with_hi(value.span.lo() + BytePos(1)), - value.span.with_lo(value.span.hi() - BytePos(1)), - ) + let expr_span = expr.span.find_ancestor_inside(value.span); + if let Some(expr_span) = expr_span { + Some((value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi()))) } else { - (value.span.with_hi(expr.span.lo()), value.span.with_lo(expr.span.hi())) + None } } _ => return, @@ -529,36 +529,38 @@ trait UnusedDelimLint { left_pos.map_or(false, |s| s >= value.span.lo()), right_pos.map_or(false, |s| s <= value.span.hi()), ); - self.emit_unused_delims(cx, spans, ctx.into(), keep_space); + self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space); } fn emit_unused_delims( &self, cx: &EarlyContext<'_>, - spans: (Span, Span), + value_span: Span, + spans: Option<(Span, Span)>, msg: &str, keep_space: (bool, bool), ) { - // FIXME(flip1995): Quick and dirty fix for #70814. This should be fixed in rustdoc - // properly. - if spans.0 == DUMMY_SP || spans.1 == DUMMY_SP { - return; - } - - cx.struct_span_lint(self.lint(), MultiSpan::from(vec![spans.0, spans.1]), |lint| { - let replacement = vec![ - (spans.0, if keep_space.0 { " ".into() } else { "".into() }), - (spans.1, if keep_space.1 { " ".into() } else { "".into() }), - ]; - lint.build(fluent::lint::unused_delim) - .set_arg("delim", Self::DELIM_STR) - .set_arg("item", msg) - .multipart_suggestion( + let primary_span = if let Some((lo, hi)) = spans { + MultiSpan::from(vec![lo, hi]) + } else { + MultiSpan::from(value_span) + }; + cx.struct_span_lint(self.lint(), primary_span, |lint| { + let mut db = lint.build(fluent::lint::unused_delim); + db.set_arg("delim", Self::DELIM_STR); + db.set_arg("item", msg); + if let Some((lo, hi)) = spans { + let replacement = vec![ + (lo, if keep_space.0 { " ".into() } else { "".into() }), + (hi, if keep_space.1 { " ".into() } else { "".into() }), + ]; + db.multipart_suggestion( fluent::lint::suggestion, replacement, Applicability::MachineApplicable, - ) - .emit(); + ); + } + db.emit(); }); } @@ -606,8 +608,7 @@ trait UnusedDelimLint { ref call_or_other => { let (args_to_check, ctx) = match *call_or_other { Call(_, ref args) => (&args[..], UnusedDelimsCtx::FunctionArg), - // first "argument" is self (which sometimes needs delims) - MethodCall(_, ref args, _) => (&args[1..], UnusedDelimsCtx::MethodArg), + MethodCall(_, _, ref args, _) => (&args[..], UnusedDelimsCtx::MethodArg), // actual catch-all arm _ => { return; @@ -766,15 +767,12 @@ impl UnusedParens { // Otherwise proceed with linting. _ => {} } - let spans = if value.span.from_expansion() || inner.span.from_expansion() { - ( - value.span.with_hi(value.span.lo() + BytePos(1)), - value.span.with_lo(value.span.hi() - BytePos(1)), - ) + let spans = if let Some(inner) = inner.span.find_ancestor_inside(value.span) { + Some((value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi()))) } else { - (value.span.with_hi(inner.span.lo()), value.span.with_lo(inner.span.hi())) + None }; - self.emit_unused_delims(cx, spans, "pattern", (false, false)); + self.emit_unused_delims(cx, value.span, spans, "pattern", (false, false)); } } } @@ -879,15 +877,12 @@ impl EarlyLintPass for UnusedParens { ); } _ => { - let spans = if ty.span.from_expansion() || r.span.from_expansion() { - ( - ty.span.with_hi(ty.span.lo() + BytePos(1)), - ty.span.with_lo(ty.span.hi() - BytePos(1)), - ) + let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) { + Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi()))) } else { - (ty.span.with_hi(r.span.lo()), ty.span.with_lo(r.span.hi())) + None }; - self.emit_unused_delims(cx, spans, "type", (false, false)); + self.emit_unused_delims(cx, ty.span, spans, "type", (false, false)); } } } diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 62ef5804dce..abb68f3afe5 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -242,6 +242,13 @@ fn main() { println!("cargo:rustc-link-lib=uuid"); } else if target.contains("netbsd") || target.contains("haiku") || target.contains("darwin") { println!("cargo:rustc-link-lib=z"); + } else if target.starts_with("arm") + || target.starts_with("mips-") + || target.starts_with("mipsel-") + || target.starts_with("powerpc-") + { + // 32-bit targets need to link libatomic. + println!("cargo:rustc-link-lib=atomic"); } cmd.args(&components); diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs index 9f6079ecba4..c5e39507d7e 100644 --- a/compiler/rustc_metadata/src/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -328,7 +328,31 @@ impl<'tcx> Collector<'tcx> { .map(|child_item| self.build_dll_import(abi, child_item)) .collect() } - _ => Vec::new(), + _ => { + for child_item in foreign_mod_items { + if self.tcx.def_kind(child_item.id.def_id).has_codegen_attrs() + && self + .tcx + .codegen_fn_attrs(child_item.id.def_id) + .link_ordinal + .is_some() + { + let link_ordinal_attr = self + .tcx + .hir() + .attrs(self.tcx.hir().local_def_id_to_hir_id(child_item.id.def_id)) + .iter() + .find(|a| a.has_name(sym::link_ordinal)) + .unwrap(); + sess.span_err( + link_ordinal_attr.span, + "`#[link_ordinal]` is only supported if link kind is `raw-dylib`", + ); + } + } + + Vec::new() + } }; self.libs.push(NativeLib { name: name.map(|(name, _)| name), diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 45c6468bc24..4e1254efd17 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -26,7 +26,6 @@ #![feature(allocator_api)] #![feature(array_windows)] #![feature(assert_matches)] -#![feature(backtrace)] #![feature(box_patterns)] #![feature(core_intrinsics)] #![feature(discriminant_kind)] diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs index b856af1d8f8..5e26a52900e 100644 --- a/compiler/rustc_middle/src/thir.rs +++ b/compiler/rustc_middle/src/thir.rs @@ -814,8 +814,8 @@ impl<'tcx> fmt::Display for Pat<'tcx> { mod size_asserts { use super::*; // These are in alphabetical order, which is easy to maintain. - rustc_data_structures::static_assert_size!(Block, 56); - rustc_data_structures::static_assert_size!(Expr<'_>, 104); - rustc_data_structures::static_assert_size!(Pat<'_>, 24); - rustc_data_structures::static_assert_size!(Stmt<'_>, 120); + static_assert_size!(Block, 56); + static_assert_size!(Expr<'_>, 104); + static_assert_size!(Pat<'_>, 24); + static_assert_size!(Stmt<'_>, 120); } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 79309097e78..a7833ab6431 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -594,6 +594,29 @@ impl<'tcx> Predicate<'tcx> { } self } + + /// Whether this projection can be soundly normalized. + /// + /// Wf predicates must not be normalized, as normalization + /// can remove required bounds which would cause us to + /// unsoundly accept some programs. See #91068. + #[inline] + pub fn allow_normalization(self) -> bool { + match self.kind().skip_binder() { + PredicateKind::WellFormed(_) => false, + PredicateKind::Trait(_) + | PredicateKind::RegionOutlives(_) + | PredicateKind::TypeOutlives(_) + | PredicateKind::Projection(_) + | PredicateKind::ObjectSafe(_) + | PredicateKind::ClosureKind(_, _, _) + | PredicateKind::Subtype(_) + | PredicateKind::Coerce(_) + | PredicateKind::ConstEvaluatable(_) + | PredicateKind::ConstEquate(_, _) + | PredicateKind::TypeWellFormedFromEnv(_) => true, + } + } } impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Predicate<'tcx> { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 7f2e81a71a9..cc55b7e8611 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1513,6 +1513,10 @@ pub trait PrettyPrinter<'tcx>: } return Ok(self); } + (ty::ValTree::Leaf(leaf), ty::Ref(_, inner_ty, _)) => { + p!(write("&")); + return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty); + } (ty::ValTree::Leaf(leaf), _) => { return self.pretty_print_const_scalar_int(leaf, ty, print_ty); } diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index cefb5f36b6a..ce38283724d 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -170,7 +170,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut arm_candidates = self.create_match_candidates(scrutinee_place.clone(), &arms); - let match_has_guard = arms.iter().copied().any(|arm| self.thir[arm].guard.is_some()); + let match_has_guard = arm_candidates.iter().any(|(_, candidate)| candidate.has_guard); let mut candidates = arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>(); diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs index d6dd0f01794..f2045ac19ca 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -168,7 +168,12 @@ impl<'a, 'tcx> ConstToPat<'a, 'tcx> { // once indirect_structural_match is a full fledged error, this // level of indirection can be eliminated - let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap(); + let inlined_const_as_pat = + self.recur(cv, mir_structural_match_violation).unwrap_or_else(|_| Pat { + span: self.span, + ty: cv.ty(), + kind: Box::new(PatKind::Constant { value: cv }), + }); if self.include_lint_checks && !self.saw_const_match_error.get() { // If we were able to successfully convert the const to some pat, diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 98016659a05..1c087b93b49 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -183,6 +183,18 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> type MemoryKind = !; + #[inline(always)] + fn enforce_alignment(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + // We do not check for alignment to avoid having to carry an `Align` + // in `ConstValue::ByRef`. + false + } + + #[inline(always)] + fn enforce_validity(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + false // for now, we don't enforce validity + } + fn load_mir( _ecx: &InterpCx<'mir, 'tcx, Self>, _instance: ty::InstanceDef<'tcx>, diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs index 76b4cdd2ecd..76522233689 100644 --- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs +++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs @@ -70,7 +70,6 @@ impl<'tcx, 'a> MutVisitor<'tcx> for ElaborateBoxDerefVisitor<'tcx, 'a> { build_ptr_tys(tcx, base_ty.boxed_ty(), self.unique_did, self.nonnull_did); let ptr_local = self.patch.new_temp(ptr_ty, source_info.span); - self.local_decls.push(LocalDecl::new(ptr_ty, source_info.span)); self.patch.add_statement(location, StatementKind::StorageLive(ptr_local)); @@ -125,13 +124,6 @@ impl<'tcx> MirPass<'tcx> for ElaborateBoxDerefs { index += 1; } - if let Some(terminator) = terminator - && !matches!(terminator.kind, TerminatorKind::Yield{..}) - { - let location = Location { block, statement_index: index }; - visitor.visit_terminator(terminator, location); - } - let location = Location { block, statement_index: index }; match terminator { // yielding into a box is handled when lowering generators diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 40dc9fe9a05..2a51af582f5 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -29,7 +29,6 @@ use rustc_middle::mir::visit::Visitor as _; use rustc_middle::mir::{traversal, Body, ConstQualifs, MirPass, MirPhase, Promoted}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitable}; -use rustc_span::{Span, Symbol}; #[macro_use] mod pass_manager; @@ -159,14 +158,7 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> { set: &'a mut FxIndexSet<LocalDefId>, } impl<'tcx> Visitor<'tcx> for GatherCtors<'_, 'tcx> { - fn visit_variant_data( - &mut self, - v: &'tcx hir::VariantData<'tcx>, - _: Symbol, - _: &'tcx hir::Generics<'tcx>, - _: hir::HirId, - _: Span, - ) { + fn visit_variant_data(&mut self, v: &'tcx hir::VariantData<'tcx>) { if let hir::VariantData::Tuple(_, hir_id) = *v { self.set.insert(self.tcx.hir().local_def_id(hir_id)); } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index a2155ac1d1a..f4c6b33a529 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -19,7 +19,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ fluent, Applicability, DiagnosticBuilder, DiagnosticMessage, Handler, MultiSpan, PResult, }; -use rustc_errors::{pluralize, struct_span_err, Diagnostic, EmissionGuarantee, ErrorGuaranteed}; +use rustc_errors::{pluralize, struct_span_err, Diagnostic, ErrorGuaranteed}; use rustc_macros::{SessionDiagnostic, SessionSubdiagnostic}; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, Ident}; @@ -228,13 +228,13 @@ struct MultiSugg { } impl MultiSugg { - fn emit<G: EmissionGuarantee>(self, err: &mut DiagnosticBuilder<'_, G>) { + fn emit(self, err: &mut Diagnostic) { err.multipart_suggestion(&self.msg, self.patches, self.applicability); } /// Overrides individual messages and applicabilities. - fn emit_many<G: EmissionGuarantee>( - err: &mut DiagnosticBuilder<'_, G>, + fn emit_many( + err: &mut Diagnostic, msg: &str, applicability: Applicability, suggestions: impl Iterator<Item = Self>, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index e473f4d30cf..2880ef78c8d 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -850,7 +850,7 @@ impl<'a> Parser<'a> { ExprKind::Index(_, _) => "indexing", ExprKind::Try(_) => "`?`", ExprKind::Field(_, _) => "a field access", - ExprKind::MethodCall(_, _, _) => "a method call", + ExprKind::MethodCall(_, _, _, _) => "a method call", ExprKind::Call(_, _) => "a function call", ExprKind::Await(_) => "`.await`", ExprKind::Err => return Ok(with_postfix), @@ -859,7 +859,7 @@ impl<'a> Parser<'a> { ); let mut err = self.struct_span_err(span, &msg); - let suggest_parens = |err: &mut DiagnosticBuilder<'_, _>| { + let suggest_parens = |err: &mut Diagnostic| { let suggestions = vec![ (span.shrink_to_lo(), "(".to_string()), (span.shrink_to_hi(), ")".to_string()), @@ -1258,8 +1258,11 @@ impl<'a> Parser<'a> { /// Parse an indexing expression `expr[...]`. fn parse_index_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> { + let prev_span = self.prev_token.span; + let open_delim_span = self.token.span; self.bump(); // `[` let index = self.parse_expr()?; + self.suggest_missing_semicolon_before_array(prev_span, open_delim_span)?; self.expect(&token::CloseDelim(Delimiter::Bracket))?; Ok(self.mk_expr(lo.to(self.prev_token.span), self.mk_index(base, index), AttrVec::new())) } @@ -1277,12 +1280,14 @@ impl<'a> Parser<'a> { if self.check(&token::OpenDelim(Delimiter::Parenthesis)) { // Method call `expr.f()` - let mut args = self.parse_paren_expr_seq()?; - args.insert(0, self_arg); - + let args = self.parse_paren_expr_seq()?; let fn_span = fn_span_lo.to(self.prev_token.span); let span = lo.to(self.prev_token.span); - Ok(self.mk_expr(span, ExprKind::MethodCall(segment, args, fn_span), AttrVec::new())) + Ok(self.mk_expr( + span, + ExprKind::MethodCall(segment, self_arg, args, fn_span), + AttrVec::new(), + )) } else { // Field access `expr.f` if let Some(args) = segment.args { @@ -2056,6 +2061,45 @@ impl<'a> Parser<'a> { } } + fn suggest_missing_semicolon_before_array( + &self, + prev_span: Span, + open_delim_span: Span, + ) -> PResult<'a, ()> { + if self.token.kind == token::Comma { + let mut snapshot = self.create_snapshot_for_diagnostic(); + snapshot.bump(); + match snapshot.parse_seq_to_before_end( + &token::CloseDelim(Delimiter::Bracket), + SeqSep::trailing_allowed(token::Comma), + |p| p.parse_expr(), + ) { + Ok(_) + // When the close delim is `)`, `token.kind` is expected to be `token::CloseDelim(Delimiter::Parenthesis)`, + // but the actual `token.kind` is `token::CloseDelim(Delimiter::Bracket)`. + // This is because the `token.kind` of the close delim is treated as the same as + // that of the open delim in `TokenTreesReader::parse_token_tree`, even if the delimiters of them are different. + // Therefore, `token.kind` should not be compared here. + if snapshot + .span_to_snippet(snapshot.token.span) + .map_or(false, |snippet| snippet == "]") => + { + let mut err = self.struct_span_err(open_delim_span, "expected `;`, found `[`"); + err.span_suggestion_verbose( + prev_span.shrink_to_hi(), + "consider adding `;` here", + ';', + Applicability::MaybeIncorrect, + ); + return Err(err); + } + Ok(_) => (), + Err(err) => err.cancel(), + } + } + Ok(()) + } + /// Parses a block or unsafe block. pub(super) fn parse_block_expr( &mut self, diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 0c523ad22c2..c088b6e1e0e 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1295,7 +1295,11 @@ impl<'a> Parser<'a> { self.bump(); // `in` let path = self.parse_path(PathStyle::Mod)?; // `path` self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` - let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; + let vis = VisibilityKind::Restricted { + path: P(path), + id: ast::DUMMY_NODE_ID, + shorthand: false, + }; return Ok(Visibility { span: lo.to(self.prev_token.span), kind: vis, @@ -1308,7 +1312,11 @@ impl<'a> Parser<'a> { self.bump(); // `(` let path = self.parse_path(PathStyle::Mod)?; // `crate`/`super`/`self` self.expect(&token::CloseDelim(Delimiter::Parenthesis))?; // `)` - let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; + let vis = VisibilityKind::Restricted { + path: P(path), + id: ast::DUMMY_NODE_ID, + shorthand: true, + }; return Ok(Visibility { span: lo.to(self.prev_token.span), kind: vis, diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 6fea68ce8b3..f75fffb6871 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -2066,14 +2066,9 @@ impl<'tcx> Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_expr(self, expr) } - fn visit_variant( - &mut self, - variant: &'tcx hir::Variant<'tcx>, - generics: &'tcx hir::Generics<'tcx>, - item_id: HirId, - ) { + fn visit_variant(&mut self, variant: &'tcx hir::Variant<'tcx>) { self.check_attributes(variant.id, variant.span, Target::Variant, None); - intravisit::walk_variant(self, variant, generics, item_id) + intravisit::walk_variant(self, variant) } fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 1e2fbeb384c..625c854ea77 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -368,14 +368,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { self.maybe_typeck_results = old_maybe_typeck_results; } - fn visit_variant_data( - &mut self, - def: &'tcx hir::VariantData<'tcx>, - _: Symbol, - _: &hir::Generics<'_>, - _: hir::HirId, - _: rustc_span::Span, - ) { + fn visit_variant_data(&mut self, def: &'tcx hir::VariantData<'tcx>) { let tcx = self.tcx; let has_repr_c = self.repr_has_repr_c; let has_repr_simd = self.repr_has_repr_simd; diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index a3be827a7cc..399d00b403a 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -21,21 +21,55 @@ enum Id { None, } -struct NodeData { +struct NodeStats { count: usize, size: usize, } +impl NodeStats { + fn new() -> NodeStats { + NodeStats { count: 0, size: 0 } + } +} + +struct Node { + stats: NodeStats, + subnodes: FxHashMap<&'static str, NodeStats>, +} + +impl Node { + fn new() -> Node { + Node { stats: NodeStats::new(), subnodes: FxHashMap::default() } + } +} + +/// This type measures the size of AST and HIR nodes, by implementing the AST +/// and HIR `Visitor` traits. But we don't measure every visited type because +/// that could cause double counting. +/// +/// For example, `ast::Visitor` has `visit_ident`, but `Ident`s are always +/// stored inline within other AST nodes, so we don't implement `visit_ident` +/// here. In constrast, we do implement `visit_expr` because `ast::Expr` is +/// always stored as `P<ast::Expr>`, and every such expression should be +/// measured separately. +/// +/// In general, a `visit_foo` method should be implemented here if the +/// corresponding `Foo` type is always stored on its own, e.g.: `P<Foo>`, +/// `Box<Foo>`, `Vec<Foo>`, `Box<[Foo]>`. +/// +/// There are some types in the AST and HIR tree that the visitors do not have +/// a `visit_*` method for, and so we cannot measure these, which is +/// unfortunate. struct StatCollector<'k> { krate: Option<Map<'k>>, - data: FxHashMap<&'static str, NodeData>, + nodes: FxHashMap<&'static str, Node>, seen: FxHashSet<Id>, } pub fn print_hir_stats(tcx: TyCtxt<'_>) { let mut collector = StatCollector { krate: Some(tcx.hir()), - data: FxHashMap::default(), + nodes: FxHashMap::default(), seen: FxHashSet::default(), }; tcx.hir().walk_toplevel_module(&mut collector); @@ -44,49 +78,88 @@ pub fn print_hir_stats(tcx: TyCtxt<'_>) { } pub fn print_ast_stats(krate: &ast::Crate, title: &str) { + use rustc_ast::visit::Visitor; + let mut collector = - StatCollector { krate: None, data: FxHashMap::default(), seen: FxHashSet::default() }; - ast_visit::walk_crate(&mut collector, krate); + StatCollector { krate: None, nodes: FxHashMap::default(), seen: FxHashSet::default() }; + collector.visit_crate(krate); collector.print(title); } impl<'k> StatCollector<'k> { - fn record<T>(&mut self, label: &'static str, id: Id, node: &T) { + // Record a top-level node. + fn record<T>(&mut self, label: &'static str, id: Id, val: &T) { + self.record_inner(label, None, id, val); + } + + // Record a two-level entry, with a top-level enum type and a variant. + fn record_variant<T>(&mut self, label1: &'static str, label2: &'static str, id: Id, val: &T) { + self.record_inner(label1, Some(label2), id, val); + } + + fn record_inner<T>( + &mut self, + label1: &'static str, + label2: Option<&'static str>, + id: Id, + val: &T, + ) { if id != Id::None && !self.seen.insert(id) { return; } - let entry = self.data.entry(label).or_insert(NodeData { count: 0, size: 0 }); + let node = self.nodes.entry(label1).or_insert(Node::new()); + node.stats.count += 1; + node.stats.size = std::mem::size_of_val(val); - entry.count += 1; - entry.size = std::mem::size_of_val(node); + if let Some(label2) = label2 { + let subnode = node.subnodes.entry(label2).or_insert(NodeStats::new()); + subnode.count += 1; + subnode.size = std::mem::size_of_val(val); + } } fn print(&self, title: &str) { - let mut stats: Vec<_> = self.data.iter().collect(); + let mut nodes: Vec<_> = self.nodes.iter().collect(); + nodes.sort_by_key(|&(_, ref node)| node.stats.count * node.stats.size); - stats.sort_by_key(|&(_, ref d)| d.count * d.size); - - let mut total_size = 0; + let total_size = nodes.iter().map(|(_, node)| node.stats.count * node.stats.size).sum(); eprintln!("\n{}\n", title); eprintln!("{:<18}{:>18}{:>14}{:>14}", "Name", "Accumulated Size", "Count", "Item Size"); eprintln!("----------------------------------------------------------------"); - for (label, data) in stats { + let percent = |m, n| (m * 100) as f64 / n as f64; + + for (label, node) in nodes { + let size = node.stats.count * node.stats.size; eprintln!( - "{:<18}{:>18}{:>14}{:>14}", + "{:<18}{:>10} ({:4.1}%){:>14}{:>14}", label, - to_readable_str(data.count * data.size), - to_readable_str(data.count), - to_readable_str(data.size) + to_readable_str(size), + percent(size, total_size), + to_readable_str(node.stats.count), + to_readable_str(node.stats.size) ); - - total_size += data.count * data.size; + if !node.subnodes.is_empty() { + let mut subnodes: Vec<_> = node.subnodes.iter().collect(); + subnodes.sort_by_key(|&(_, ref subnode)| subnode.count * subnode.size); + + for (label, subnode) in subnodes { + let size = subnode.count * subnode.size; + eprintln!( + "- {:<18}{:>10} ({:4.1}%){:>14}", + label, + to_readable_str(size), + percent(size, total_size), + to_readable_str(subnode.count), + ); + } + } } eprintln!("----------------------------------------------------------------"); - eprintln!("{:<18}{:>18}\n", "Total", to_readable_str(total_size)); + eprintln!("{:<18}{:>10}\n", "Total", to_readable_str(total_size)); } } @@ -203,14 +276,9 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_field_def(self, s) } - fn visit_variant( - &mut self, - v: &'v hir::Variant<'v>, - g: &'v hir::Generics<'v>, - item_id: hir::HirId, - ) { + fn visit_variant(&mut self, v: &'v hir::Variant<'v>) { self.record("Variant", Id::None, v); - hir_visit::walk_variant(self, v, g, item_id) + hir_visit::walk_variant(self, v) } fn visit_lifetime(&mut self, lifetime: &'v hir::Lifetime) { @@ -228,6 +296,10 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { hir_visit::walk_path(self, path) } + // `PathSegment` has one inline use (in `ast::ExprKind::MethodCall`) and + // one non-inline use (in `Path::segments`). The latter case is more common + // than the former case, so we implement this visitor and tolerate the + // double counting in the former case. fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v hir::PathSegment<'v>) { self.record("PathSegment", Id::None, path_segment); hir_visit::walk_path_segment(self, path_span, path_segment) @@ -243,14 +315,54 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> { } } +// Used to avoid boilerplate for types with many variants. +macro_rules! record_variants { + ( + ($self:ident, $val:expr, $kind:expr, $ty:ty, $tykind:ident), // mandatory pieces + [$($variant:ident),*] + ) => { + match $kind { + $( + ast::$tykind::$variant { .. } => { + $self.record_variant(stringify!($ty), stringify!($variant), Id::None, $val) + } + )* + } + }; +} + impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { fn visit_foreign_item(&mut self, i: &'v ast::ForeignItem) { - self.record("ForeignItem", Id::None, i); + record_variants!( + (self, i, i.kind, ForeignItem, ForeignItemKind), + [Static, Fn, TyAlias, MacCall] + ); ast_visit::walk_foreign_item(self, i) } fn visit_item(&mut self, i: &'v ast::Item) { - self.record("Item", Id::None, i); + record_variants!( + (self, i, i.kind, Item, ItemKind), + [ + ExternCrate, + Use, + Static, + Const, + Fn, + Mod, + ForeignMod, + GlobalAsm, + TyAlias, + Enum, + Struct, + Union, + Trait, + TraitAlias, + Impl, + MacCall, + MacroDef + ] + ); ast_visit::walk_item(self, i) } @@ -265,47 +377,116 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { } fn visit_stmt(&mut self, s: &'v ast::Stmt) { - self.record("Stmt", Id::None, s); + record_variants!( + (self, s, s.kind, Stmt, StmtKind), + [Local, Item, Expr, Semi, Empty, MacCall] + ); ast_visit::walk_stmt(self, s) } + fn visit_param(&mut self, p: &'v ast::Param) { + self.record("Param", Id::None, p); + ast_visit::walk_param(self, p) + } + fn visit_arm(&mut self, a: &'v ast::Arm) { self.record("Arm", Id::None, a); ast_visit::walk_arm(self, a) } fn visit_pat(&mut self, p: &'v ast::Pat) { - self.record("Pat", Id::None, p); + record_variants!( + (self, p, p.kind, Pat, PatKind), + [ + Wild, + Ident, + Struct, + TupleStruct, + Or, + Path, + Tuple, + Box, + Ref, + Lit, + Range, + Slice, + Rest, + Paren, + MacCall + ] + ); ast_visit::walk_pat(self, p) } - fn visit_expr(&mut self, ex: &'v ast::Expr) { - self.record("Expr", Id::None, ex); - ast_visit::walk_expr(self, ex) + fn visit_expr(&mut self, e: &'v ast::Expr) { + record_variants!( + (self, e, e.kind, Expr, ExprKind), + [ + Box, Array, ConstBlock, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type, Let, + If, While, ForLoop, Loop, Match, Closure, Block, Async, Await, TryBlock, Assign, + AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, + InlineAsm, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, Err + ] + ); + ast_visit::walk_expr(self, e) } fn visit_ty(&mut self, t: &'v ast::Ty) { - self.record("Ty", Id::None, t); + record_variants!( + (self, t, t.kind, Ty, TyKind), + [ + Slice, + Array, + Ptr, + Rptr, + BareFn, + Never, + Tup, + Path, + TraitObject, + ImplTrait, + Paren, + Typeof, + Infer, + ImplicitSelf, + MacCall, + Err, + CVarArgs + ] + ); + ast_visit::walk_ty(self, t) } + fn visit_generic_param(&mut self, g: &'v ast::GenericParam) { + self.record("GenericParam", Id::None, g); + ast_visit::walk_generic_param(self, g) + } + + fn visit_where_predicate(&mut self, p: &'v ast::WherePredicate) { + record_variants!( + (self, p, p, WherePredicate, WherePredicate), + [BoundPredicate, RegionPredicate, EqPredicate] + ); + ast_visit::walk_where_predicate(self, p) + } + fn visit_fn(&mut self, fk: ast_visit::FnKind<'v>, s: Span, _: NodeId) { self.record("FnDecl", Id::None, fk.decl()); ast_visit::walk_fn(self, fk, s) } - fn visit_assoc_item(&mut self, item: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) { - let label = match ctxt { - ast_visit::AssocCtxt::Trait => "TraitItem", - ast_visit::AssocCtxt::Impl => "ImplItem", - }; - self.record(label, Id::None, item); - ast_visit::walk_assoc_item(self, item, ctxt); + fn visit_assoc_item(&mut self, i: &'v ast::AssocItem, ctxt: ast_visit::AssocCtxt) { + record_variants!( + (self, i, i.kind, AssocItem, AssocItemKind), + [Const, Fn, TyAlias, MacCall] + ); + ast_visit::walk_assoc_item(self, i, ctxt); } - fn visit_param_bound(&mut self, bounds: &'v ast::GenericBound, _ctxt: BoundKind) { - self.record("GenericBound", Id::None, bounds); - ast_visit::walk_param_bound(self, bounds) + fn visit_param_bound(&mut self, b: &'v ast::GenericBound, _ctxt: BoundKind) { + record_variants!((self, b, b, GenericBound, GenericBound), [Trait, Outlives]); + ast_visit::walk_param_bound(self, b) } fn visit_field_def(&mut self, s: &'v ast::FieldDef) { @@ -318,27 +499,42 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { ast_visit::walk_variant(self, v) } - fn visit_lifetime(&mut self, lifetime: &'v ast::Lifetime, _: ast_visit::LifetimeCtxt) { - self.record("Lifetime", Id::None, lifetime); - ast_visit::walk_lifetime(self, lifetime) - } - - fn visit_mac_call(&mut self, mac: &'v ast::MacCall) { - self.record("MacCall", Id::None, mac); - ast_visit::walk_mac(self, mac) - } + // `UseTree` has one inline use (in `ast::ItemKind::Use`) and one + // non-inline use (in `ast::UseTreeKind::Nested). The former case is more + // common, so we don't implement `visit_use_tree` and tolerate the missed + // coverage in the latter case. fn visit_path_segment(&mut self, path_span: Span, path_segment: &'v ast::PathSegment) { self.record("PathSegment", Id::None, path_segment); ast_visit::walk_path_segment(self, path_span, path_segment) } - fn visit_assoc_constraint(&mut self, constraint: &'v ast::AssocConstraint) { - self.record("AssocConstraint", Id::None, constraint); - ast_visit::walk_assoc_constraint(self, constraint) + // `GenericArgs` has one inline use (in `ast::AssocConstraint::gen_args`) and one + // non-inline use (in `ast::PathSegment::args`). The latter case is more + // common, so we implement `visit_generic_args` and tolerate the double + // counting in the former case. + fn visit_generic_args(&mut self, sp: Span, g: &'v ast::GenericArgs) { + record_variants!((self, g, g, GenericArgs, GenericArgs), [AngleBracketed, Parenthesized]); + ast_visit::walk_generic_args(self, sp, g) } fn visit_attribute(&mut self, attr: &'v ast::Attribute) { - self.record("Attribute", Id::None, attr); + record_variants!((self, attr, attr.kind, Attribute, AttrKind), [Normal, DocComment]); + ast_visit::walk_attribute(self, attr) + } + + fn visit_expr_field(&mut self, f: &'v ast::ExprField) { + self.record("ExprField", Id::None, f); + ast_visit::walk_expr_field(self, f) + } + + fn visit_crate(&mut self, krate: &'v ast::Crate) { + self.record("Crate", Id::None, krate); + ast_visit::walk_crate(self, krate) + } + + fn visit_inline_asm(&mut self, asm: &'v ast::InlineAsm) { + self.record("InlineAsm", Id::None, asm); + ast_visit::walk_inline_asm(self, asm) } } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index be920601ee4..574e8073d8e 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -11,7 +11,7 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; use rustc_hir::hir_id::CRATE_HIR_ID; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{FieldDef, Generics, HirId, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; +use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index}; @@ -442,7 +442,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ); } - fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) { + fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { self.annotate( self.tcx.hir().local_def_id(var.id), var.span, @@ -465,7 +465,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { ); } - intravisit::walk_variant(v, var, g, item_id) + intravisit::walk_variant(v, var) }, ) } @@ -598,9 +598,9 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { intravisit::walk_impl_item(self, ii); } - fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) { + fn visit_variant(&mut self, var: &'tcx Variant<'tcx>) { self.check_missing_stability(self.tcx.hir().local_def_id(var.id), var.span); - intravisit::walk_variant(self, var, g, item_id); + intravisit::walk_variant(self, var); } fn visit_field_def(&mut self, s: &'tcx FieldDef<'tcx>) { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index c28d0569d4c..f7c28eff55b 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1625,15 +1625,10 @@ impl<'a, 'tcx> Visitor<'tcx> for ObsoleteVisiblePrivateTypesVisitor<'a, 'tcx> { intravisit::walk_ty(self, t) } - fn visit_variant( - &mut self, - v: &'tcx hir::Variant<'tcx>, - g: &'tcx hir::Generics<'tcx>, - item_id: hir::HirId, - ) { + fn visit_variant(&mut self, v: &'tcx hir::Variant<'tcx>) { if self.access_levels.is_reachable(self.tcx.hir().local_def_id(v.id)) { self.in_variant = true; - intravisit::walk_variant(self, v, g, item_id); + intravisit::walk_variant(self, v); self.in_variant = false; } } diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ac8d26fb072..58a4cff55db 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -723,7 +723,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.diagnostic_metadata.current_trait_object = prev; self.diagnostic_metadata.current_type_path = prev_ty; } - fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef, _: &'ast TraitBoundModifier) { + fn visit_poly_trait_ref(&mut self, tref: &'ast PolyTraitRef) { let span = tref.span.shrink_to_lo().to(tref.trait_ref.path.span.shrink_to_lo()); self.with_generic_param_rib( &tref.bound_generic_params, @@ -3796,9 +3796,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::Field(ref subexpression, _) => { self.resolve_expr(subexpression, Some(expr)); } - ExprKind::MethodCall(ref segment, ref arguments, _) => { - let mut arguments = arguments.iter(); - self.resolve_expr(arguments.next().unwrap(), Some(expr)); + ExprKind::MethodCall(ref segment, ref receiver, ref arguments, _) => { + self.resolve_expr(receiver, Some(expr)); for argument in arguments { self.resolve_expr(argument, None); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 2b1f2b88ec4..cb133841bca 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2021,9 +2021,9 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn suggest_introducing_lifetime( &self, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + err: &mut Diagnostic, name: Option<&str>, - suggest: impl Fn(&mut DiagnosticBuilder<'_, ErrorGuaranteed>, bool, Span, &str, String) -> bool, + suggest: impl Fn(&mut Diagnostic, bool, Span, &str, String) -> bool, ) { let mut suggest_note = true; for rib in self.lifetime_ribs.iter().rev() { @@ -2149,7 +2149,7 @@ impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { pub(crate) fn add_missing_lifetime_specifiers_label( &mut self, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + err: &mut Diagnostic, lifetime_refs: Vec<MissingLifetime>, function_param_lifetimes: Option<(Vec<MissingLifetime>, Vec<ElisionFnParameter>)>, ) { diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 1827f1c208d..0032dd7d113 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -1310,6 +1310,8 @@ options! { "emit the bc module with thin LTO info (default: yes)"), export_executable_symbols: bool = (false, parse_bool, [TRACKED], "export symbols from executables, as if they were dynamic libraries"), + extra_const_ub_checks: bool = (false, parse_bool, [TRACKED], + "turns on more checks to detect const UB, which can be slow (default: no)"), #[cfg_attr(not(bootstrap), rustc_lint_opt_deny_field_access("use `Session::fewer_names` instead of this field"))] fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index 577126a95cc..639ce64a9f5 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -14,7 +14,6 @@ mod m68k; mod mips; mod mips64; mod msp430; -mod nvptx; mod nvptx64; mod powerpc; mod powerpc64; @@ -702,7 +701,6 @@ impl<'a, Ty> FnAbi<'a, Ty> { "msp430" => msp430::compute_abi_info(self), "sparc" => sparc::compute_abi_info(cx, self), "sparc64" => sparc64::compute_abi_info(cx, self), - "nvptx" => nvptx::compute_abi_info(self), "nvptx64" => { if cx.target_spec().adjust_abi(abi) == spec::abi::Abi::PtxKernel { nvptx64::compute_ptx_kernel_abi_info(cx, self) diff --git a/compiler/rustc_target/src/abi/call/nvptx.rs b/compiler/rustc_target/src/abi/call/nvptx.rs deleted file mode 100644 index 428dd95bbcd..00000000000 --- a/compiler/rustc_target/src/abi/call/nvptx.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Reference: PTX Writer's Guide to Interoperability -// https://docs.nvidia.com/cuda/ptx-writers-guide-to-interoperability - -use crate::abi::call::{ArgAbi, FnAbi}; - -fn classify_ret<Ty>(ret: &mut ArgAbi<'_, Ty>) { - if ret.layout.is_aggregate() && ret.layout.size.bits() > 32 { - ret.make_indirect(); - } else { - ret.extend_integer_width_to(32); - } -} - -fn classify_arg<Ty>(arg: &mut ArgAbi<'_, Ty>) { - if arg.layout.is_aggregate() && arg.layout.size.bits() > 32 { - arg.make_indirect(); - } else { - arg.extend_integer_width_to(32); - } -} - -pub fn compute_abi_info<Ty>(fn_abi: &mut FnAbi<'_, Ty>) { - if !fn_abi.ret.is_ignore() { - classify_ret(&mut fn_abi.ret); - } - - for arg in &mut fn_abi.args { - if arg.is_ignore() { - continue; - } - classify_arg(arg); - } -} diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs index 9d36e37d7b8..6d919a4c2ad 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs @@ -1,20 +1,20 @@ -use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, Target, TargetOptions}; +use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions}; pub fn target() -> Target { - let mut base = super::apple_base::opts("macos"); + let arch = "arm64"; + let mut base = super::apple_base::opts("macos", arch, ""); base.cpu = "apple-a14".into(); base.max_atomic_width = Some(128); // FIXME: The leak sanitizer currently fails the tests, see #88132. base.supported_sanitizers = SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::THREAD; - base.add_pre_link_args(LinkerFlavor::Gcc, &["-arch", "arm64"]); base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove()); // Clang automatically chooses a more specific target based on // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work // correctly, we do too. - let llvm_target = super::apple_base::macos_llvm_target("arm64"); + let llvm_target = super::apple_base::macos_llvm_target(arch); Target { llvm_target: llvm_target.into(), diff --git a/compiler/rustc_target/src/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs index dc06597db6f..2bf83a8782a 100644 --- a/compiler/rustc_target/src/spec/android_base.rs +++ b/compiler/rustc_target/src/spec/android_base.rs @@ -10,6 +10,6 @@ pub fn opts() -> TargetOptions { // for context. (At that time, there was no `-C force-unwind-tables`, so the only solution // was to always emit `uwtable`). base.default_uwtable = true; - base.crt_static_respected = false; + base.crt_static_respected = true; base } diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index 15e4fb9be63..db38ff50c78 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -1,8 +1,45 @@ use std::{borrow::Cow, env}; -use crate::spec::{cvs, FramePointer, LldFlavor, SplitDebuginfo, TargetOptions}; +use crate::spec::{cvs, FramePointer, SplitDebuginfo, TargetOptions}; +use crate::spec::{LinkArgs, LinkerFlavor, LldFlavor}; + +fn pre_link_args(os: &'static str, arch: &'static str, abi: &'static str) -> LinkArgs { + let mut args = LinkArgs::new(); + + let platform_name = match abi { + "sim" => format!("{}-simulator", os), + "macabi" => "mac-catalyst".to_string(), + _ => os.to_string(), + }; + + let platform_version = match os.as_ref() { + "ios" => ios_lld_platform_version(), + "tvos" => tvos_lld_platform_version(), + "watchos" => watchos_lld_platform_version(), + "macos" => macos_lld_platform_version(arch), + _ => unreachable!(), + }; + + if abi != "macabi" { + args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), arch.into()]); + } + + args.insert( + LinkerFlavor::Lld(LldFlavor::Ld64), + vec![ + "-arch".into(), + arch.into(), + "-platform_version".into(), + platform_name.into(), + platform_version.clone().into(), + platform_version.into(), + ], + ); + + args +} -pub fn opts(os: &'static str) -> TargetOptions { +pub fn opts(os: &'static str, arch: &'static str, abi: &'static str) -> TargetOptions { // ELF TLS is only available in macOS 10.7+. If you try to compile for 10.6 // either the linker will complain if it is used or the binary will end up // segfaulting at runtime when run on 10.6. Rust by default supports macOS @@ -24,6 +61,7 @@ pub fn opts(os: &'static str) -> TargetOptions { // macOS has -dead_strip, which doesn't rely on function_sections function_sections: false, dynamic_linking: true, + pre_link_args: pre_link_args(os, arch, abi), linker_is_gnu: false, families: cvs!["unix"], is_like_osx: true, @@ -73,6 +111,11 @@ fn macos_deployment_target(arch: &str) -> (u32, u32) { .unwrap_or_else(|| macos_default_deployment_target(arch)) } +fn macos_lld_platform_version(arch: &str) -> String { + let (major, minor) = macos_deployment_target(arch); + format!("{}.{}", major, minor) +} + pub fn macos_llvm_target(arch: &str) -> String { let (major, minor) = macos_deployment_target(arch); format!("{}-apple-macosx{}.{}.0", arch, major, minor) @@ -109,7 +152,7 @@ pub fn ios_llvm_target(arch: &str) -> String { format!("{}-apple-ios{}.{}.0", arch, major, minor) } -pub fn ios_lld_platform_version() -> String { +fn ios_lld_platform_version() -> String { let (major, minor) = ios_deployment_target(); format!("{}.{}", major, minor) } @@ -123,7 +166,7 @@ fn tvos_deployment_target() -> (u32, u32) { deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((7, 0)) } -pub fn tvos_lld_platform_version() -> String { +fn tvos_lld_platform_version() -> String { let (major, minor) = tvos_deployment_target(); format!("{}.{}", major, minor) } @@ -132,7 +175,7 @@ fn watchos_deployment_target() -> (u32, u32) { deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0)) } -pub fn watchos_lld_platform_version() -> String { +fn watchos_lld_platform_version() -> String { let (major, minor) = watchos_deployment_target(); format!("{}.{}", major, minor) } diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs index d77558f0f84..bf3ebaa2840 100644 --- a/compiler/rustc_target/src/spec/apple_sdk_base.rs +++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs @@ -1,4 +1,4 @@ -use crate::spec::{cvs, LinkArgs, LinkerFlavor, LldFlavor, TargetOptions}; +use crate::spec::{cvs, TargetOptions}; use std::borrow::Cow; use Arch::*; @@ -61,53 +61,13 @@ fn link_env_remove(arch: Arch) -> Cow<'static, [Cow<'static, str>]> { } } -fn pre_link_args(os: &'static str, arch: Arch) -> LinkArgs { - let mut args = LinkArgs::new(); - - let target_abi = target_abi(arch); - - let platform_name = match target_abi { - "sim" => format!("{}-simulator", os), - "macabi" => "mac-catalyst".to_string(), - _ => os.to_string(), - }; - - let platform_version = match os.as_ref() { - "ios" => super::apple_base::ios_lld_platform_version(), - "tvos" => super::apple_base::tvos_lld_platform_version(), - "watchos" => super::apple_base::watchos_lld_platform_version(), - _ => unreachable!(), - }; - - let arch_str = target_arch_name(arch); - - if target_abi != "macabi" { - args.insert(LinkerFlavor::Gcc, vec!["-arch".into(), arch_str.into()]); - } - - args.insert( - LinkerFlavor::Lld(LldFlavor::Ld64), - vec![ - "-arch".into(), - arch_str.into(), - "-platform_version".into(), - platform_name.into(), - platform_version.clone().into(), - platform_version.into(), - ], - ); - - args -} - pub fn opts(os: &'static str, arch: Arch) -> TargetOptions { TargetOptions { abi: target_abi(arch).into(), cpu: target_cpu(arch).into(), dynamic_linking: false, - pre_link_args: pre_link_args(os, arch), link_env_remove: link_env_remove(arch), has_thread_local: false, - ..super::apple_base::opts(os) + ..super::apple_base::opts(os, target_arch_name(arch), target_abi(arch)) } } diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs index df1e3275f73..962ad0c66d9 100644 --- a/compiler/rustc_target/src/spec/fuchsia_base.rs +++ b/compiler/rustc_target/src/spec/fuchsia_base.rs @@ -1,6 +1,11 @@ use crate::spec::{crt_objects, cvs, LinkOutputKind, LinkerFlavor, LldFlavor, TargetOptions}; pub fn opts() -> TargetOptions { + // This mirrors the linker options provided by clang. We presume lld for + // now. When using clang as the linker it will supply these options for us, + // so we only list them for ld/lld. + // + // https://github.com/llvm/llvm-project/blob/db9322b2066c55254e7691efeab863f43bfcc084/clang/lib/Driver/ToolChains/Fuchsia.cpp#L31 let pre_link_args = TargetOptions::link_args( LinkerFlavor::Ld, &[ diff --git a/compiler/rustc_target/src/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs index 1718bd77b86..5e9ceb844f7 100644 --- a/compiler/rustc_target/src/spec/i686_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/i686_apple_darwin.rs @@ -1,7 +1,8 @@ use crate::spec::{FramePointer, LinkerFlavor, StackProbeType, Target, TargetOptions}; pub fn target() -> Target { - let mut base = super::apple_base::opts("macos"); + // ld64 only understand i386 and not i686 + let mut base = super::apple_base::opts("macos", "i386", ""); base.cpu = "yonah".into(); base.max_atomic_width = Some(64); base.add_pre_link_args(LinkerFlavor::Gcc, &["-m32"]); diff --git a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs index 2546ab9b7e6..c9bb0112f0e 100644 --- a/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs @@ -13,7 +13,9 @@ pub fn target() -> Target { abi: "eabi".into(), // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them // with +strict-align. - features: "+strict-align".into(), + // Also force-enable 32-bit atomics, which allows the use of atomic load/store only. + // The resulting atomics are ABI incompatible with atomics backed by libatomic. + features: "+strict-align,+atomics-32".into(), // There are no atomic CAS instructions available in the instruction set of the ARMv6-M // architecture atomic_cas: false, diff --git a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs index dbd26899c18..176c9dd6b76 100644 --- a/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs @@ -2,11 +2,12 @@ use crate::spec::TargetOptions; use crate::spec::{FramePointer, LinkerFlavor, SanitizerSet, StackProbeType, Target}; pub fn target() -> Target { - let mut base = super::apple_base::opts("macos"); + let arch = "x86_64"; + let mut base = super::apple_base::opts("macos", arch, ""); base.cpu = "core2".into(); base.max_atomic_width = Some(128); // core2 support cmpxchg16b base.frame_pointer = FramePointer::Always; - base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64", "-arch", "x86_64"]); + base.add_pre_link_args(LinkerFlavor::Gcc, &["-m64"]); base.link_env_remove.to_mut().extend(super::apple_base::macos_link_env_remove()); // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved base.stack_probes = StackProbeType::Call; @@ -16,7 +17,6 @@ pub fn target() -> Target { // Clang automatically chooses a more specific target based on // MACOSX_DEPLOYMENT_TARGET. To enable cross-language LTO to work // correctly, we do too. - let arch = "x86_64"; let llvm_target = super::apple_base::macos_llvm_target(&arch); Target { diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index adf47ece69d..74625cc7bb7 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -619,6 +619,15 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { constant.eval(self.selcx.tcx(), self.param_env) } } + + #[inline] + fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { + p.super_fold_with(self) + } else { + p + } + } } pub struct BoundVarReplacer<'me, 'tcx> { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 449d7a7b47b..61c556b726d 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -266,7 +266,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { debug!("QueryNormalizer: result = {:#?}", result); debug!("QueryNormalizer: obligations = {:#?}", obligations); self.obligations.extend(obligations); - Ok(result.normalized_ty) + + let res = result.normalized_ty; + // `tcx.normalize_projection_ty` may normalize to a type that still has + // unevaluated consts, so keep normalizing here if that's the case. + if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { + Ok(res.try_super_fold_with(self)?) + } else { + Ok(res) + } } ty::Projection(data) => { @@ -305,18 +313,27 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { debug!("QueryNormalizer: result = {:#?}", result); debug!("QueryNormalizer: obligations = {:#?}", obligations); self.obligations.extend(obligations); - Ok(crate::traits::project::PlaceholderReplacer::replace_placeholders( + + let res = crate::traits::project::PlaceholderReplacer::replace_placeholders( infcx, mapped_regions, mapped_types, mapped_consts, &self.universes, result.normalized_ty, - )) + ); + // `tcx.normalize_projection_ty` may normalize to a type that still has + // unevaluated consts, so keep normalizing here if that's the case. + if res != ty && res.has_type_flags(ty::TypeFlags::HAS_CT_PROJECTION) { + Ok(res.try_super_fold_with(self)?) + } else { + Ok(res) + } } _ => ty.try_super_fold_with(self), })()?; + self.cache.insert(ty, res); Ok(res) } @@ -351,4 +368,16 @@ impl<'cx, 'tcx> FallibleTypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { mir::ConstantKind::Val(_, _) => constant.try_super_fold_with(self)?, }) } + + #[inline] + fn try_fold_predicate( + &mut self, + p: ty::Predicate<'tcx>, + ) -> Result<ty::Predicate<'tcx>, Self::Error> { + if p.allow_normalization() && needs_normalization(&p, self.param_env.reveal()) { + p.try_super_fold_with(self) + } else { + Ok(p) + } + } } diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 8a5c7fee697..1e6cb53f3ee 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -16,7 +16,8 @@ use crate::require_c_abi_if_c_variadic; use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ - struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed, FatalError, MultiSpan, + struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError, + MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; @@ -43,7 +44,7 @@ use rustc_trait_selection::traits::error_reporting::{ }; use rustc_trait_selection::traits::wf::object_region_bounds; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; use std::collections::BTreeSet; use std::slice; @@ -367,36 +368,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { return (tcx.intern_substs(&[]), arg_count); } - let is_object = self_ty.map_or(false, |ty| ty == self.tcx().types.trait_object_dummy_self); - struct SubstsForAstPathCtxt<'a, 'tcx> { astconv: &'a (dyn AstConv<'tcx> + 'a), def_id: DefId, generic_args: &'a GenericArgs<'a>, span: Span, - missing_type_params: Vec<Symbol>, inferred_params: Vec<Span>, infer_args: bool, - is_object: bool, - } - - impl<'tcx, 'a> SubstsForAstPathCtxt<'tcx, 'a> { - fn default_needs_object_self(&mut self, param: &ty::GenericParamDef) -> bool { - let tcx = self.astconv.tcx(); - if let GenericParamDefKind::Type { has_default, .. } = param.kind { - if self.is_object && has_default { - let default_ty = tcx.at(self.span).type_of(param.def_id); - let self_param = tcx.types.self_param; - if default_ty.walk().any(|arg| arg == self_param.into()) { - // There is no suitable inference default for a type parameter - // that references self, in an object type. - return true; - } - } - } - - false - } } impl<'a, 'tcx> CreateSubstsForGenericArgsCtxt<'a, 'tcx> for SubstsForAstPathCtxt<'a, 'tcx> { @@ -499,41 +477,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { GenericParamDefKind::Type { has_default, .. } => { if !infer_args && has_default { // No type parameter provided, but a default exists. - - // If we are converting an object type, then the - // `Self` parameter is unknown. However, some of the - // other type parameters may reference `Self` in their - // defaults. This will lead to an ICE if we are not - // careful! - if self.default_needs_object_self(param) { - self.missing_type_params.push(param.name); - tcx.ty_error().into() - } else { - // This is a default type parameter. - let substs = substs.unwrap(); - if substs.iter().any(|arg| match arg.unpack() { - GenericArgKind::Type(ty) => ty.references_error(), - _ => false, - }) { - // Avoid ICE #86756 when type error recovery goes awry. - return tcx.ty_error().into(); - } - self.astconv - .normalize_ty( - self.span, - EarlyBinder(tcx.at(self.span).type_of(param.def_id)) - .subst(tcx, substs), - ) - .into() + let substs = substs.unwrap(); + if substs.iter().any(|arg| match arg.unpack() { + GenericArgKind::Type(ty) => ty.references_error(), + _ => false, + }) { + // Avoid ICE #86756 when type error recovery goes awry. + return tcx.ty_error().into(); } + self.astconv + .normalize_ty( + self.span, + EarlyBinder(tcx.at(self.span).type_of(param.def_id)) + .subst(tcx, substs), + ) + .into() } else if infer_args { - // No type parameters were provided, we can infer all. - let param = if !self.default_needs_object_self(param) { - Some(param) - } else { - None - }; - self.astconv.ty_infer(param, self.span).into() + self.astconv.ty_infer(Some(param), self.span).into() } else { // We've already errored above about the mismatch. tcx.ty_error().into() @@ -563,10 +523,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def_id, span, generic_args, - missing_type_params: vec![], inferred_params: vec![], infer_args, - is_object, }; let substs = Self::create_substs_for_generic_args( tcx, @@ -578,13 +536,6 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { &mut substs_ctx, ); - self.complain_about_missing_type_params( - substs_ctx.missing_type_params, - def_id, - span, - generic_args.args.is_empty(), - ); - debug!( "create_substs_for_ast_path(generic_params={:?}, self_ty={:?}) -> {:?}", generics, self_ty, substs @@ -1489,23 +1440,71 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Erase the `dummy_self` (`trait_object_dummy_self`) used above. let existential_trait_refs = regular_traits.iter().map(|i| { i.trait_ref().map_bound(|trait_ref: ty::TraitRef<'tcx>| { - if trait_ref.self_ty() != dummy_self { - // FIXME: There appears to be a missing filter on top of `expand_trait_aliases`, - // which picks up non-supertraits where clauses - but also, the object safety - // completely ignores trait aliases, which could be object safety hazards. We - // `delay_span_bug` here to avoid an ICE in stable even when the feature is - // disabled. (#66420) - tcx.sess.delay_span_bug( - DUMMY_SP, - &format!( - "trait_ref_to_existential called on {:?} with non-dummy Self", - trait_ref, - ), + assert_eq!(trait_ref.self_ty(), dummy_self); + + // Verify that `dummy_self` did not leak inside default type parameters. This + // could not be done at path creation, since we need to see through trait aliases. + let mut missing_type_params = vec![]; + let mut references_self = false; + let generics = tcx.generics_of(trait_ref.def_id); + let substs: Vec<_> = trait_ref + .substs + .iter() + .enumerate() + .skip(1) // Remove `Self` for `ExistentialPredicate`. + .map(|(index, arg)| { + if let ty::GenericArgKind::Type(ty) = arg.unpack() { + debug!(?ty); + if ty == dummy_self { + let param = &generics.params[index]; + missing_type_params.push(param.name); + tcx.ty_error().into() + } else if ty.walk().any(|arg| arg == dummy_self.into()) { + references_self = true; + tcx.ty_error().into() + } else { + arg + } + } else { + arg + } + }) + .collect(); + let substs = tcx.intern_substs(&substs[..]); + + let span = i.bottom().1; + let empty_generic_args = trait_bounds.iter().any(|hir_bound| { + hir_bound.trait_ref.path.res == Res::Def(DefKind::Trait, trait_ref.def_id) + && hir_bound.span.contains(span) + }); + self.complain_about_missing_type_params( + missing_type_params, + trait_ref.def_id, + span, + empty_generic_args, + ); + + if references_self { + let def_id = i.bottom().0.def_id(); + let mut err = struct_span_err!( + tcx.sess, + i.bottom().1, + E0038, + "the {} `{}` cannot be made into an object", + tcx.def_kind(def_id).descr(def_id), + tcx.item_name(def_id), + ); + err.note( + rustc_middle::traits::ObjectSafetyViolation::SupertraitSelf(smallvec![]) + .error_msg(), ); + err.emit(); } - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + + ty::ExistentialTraitRef { def_id: trait_ref.def_id, substs } }) }); + let existential_projections = bounds.projection_bounds.iter().map(|(bound, _)| { bound.map_bound(|b| { if b.projection_ty.self_ty() != dummy_self { @@ -2106,7 +2105,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { pub fn prohibit_generics<'a>( &self, segments: impl Iterator<Item = &'a hir::PathSegment<'a>> + Clone, - extend: impl Fn(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>), + extend: impl Fn(&mut Diagnostic), ) -> bool { let args = segments.clone().flat_map(|segment| segment.args().args); @@ -2984,11 +2983,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } /// Make sure that we are in the condition to suggest the blanket implementation. - fn maybe_lint_blanket_trait_impl<T: rustc_errors::EmissionGuarantee>( - &self, - self_ty: &hir::Ty<'_>, - diag: &mut DiagnosticBuilder<'_, T>, - ) { + fn maybe_lint_blanket_trait_impl(&self, self_ty: &hir::Ty<'_>, diag: &mut Diagnostic) { let tcx = self.tcx(); let parent_id = tcx.hir().get_parent_item(self_ty.hir_id); if let hir::Node::Item(hir::Item { @@ -3081,7 +3076,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { sugg, Applicability::MachineApplicable, ); - self.maybe_lint_blanket_trait_impl::<()>(&self_ty, &mut diag); + self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag); diag.emit(); }, ); diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index 7aaddc2bd7a..6c7b2a2889f 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -32,6 +32,7 @@ use super::FnCtxt; use crate::hir::def_id::DefId; use crate::type_error_struct; +use hir::def_id::LOCAL_CRATE; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; @@ -40,7 +41,7 @@ use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable}; +use rustc_middle::ty::{self, Ty, TypeAndMut, TypeVisitable, VariantDef}; use rustc_session::lint; use rustc_session::Session; use rustc_span::symbol::sym; @@ -173,6 +174,7 @@ pub enum CastError { /// or "a length". If this argument is None, then the metadata is unknown, for example, /// when we're typechecking a type parameter with a ?Sized bound. IntToFatCast(Option<&'static str>), + ForeignNonExhaustiveAdt, } impl From<ErrorGuaranteed> for CastError { @@ -591,6 +593,17 @@ impl<'a, 'tcx> CastCheck<'tcx> { } err.emit(); } + CastError::ForeignNonExhaustiveAdt => { + make_invalid_casting_error( + fcx.tcx.sess, + self.span, + self.expr_ty, + self.cast_ty, + fcx, + ) + .note("cannot cast an enum with a non-exhaustive variant when it's defined in another crate") + .emit(); + } } } @@ -789,6 +802,14 @@ impl<'a, 'tcx> CastCheck<'tcx> { _ => return Err(CastError::NonScalar), }; + if let ty::Adt(adt_def, _) = *self.expr_ty.kind() { + if adt_def.did().krate != LOCAL_CRATE { + if adt_def.variants().iter().any(VariantDef::is_field_list_non_exhaustive) { + return Err(CastError::ForeignNonExhaustiveAdt); + } + } + } + match (t_from, t_cast) { // These types have invariants! can't cast into them. (_, Int(CEnum) | FnPtr) => Err(CastError::NonScalar), diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs index 6e3ef15f884..5cdb2acd9f3 100644 --- a/compiler/rustc_typeck/src/check/check.rs +++ b/compiler/rustc_typeck/src/check/check.rs @@ -1525,9 +1525,7 @@ fn detect_discriminant_duplicate<'tcx>( ) { // Helper closure to reduce duplicate code. This gets called everytime we detect a duplicate. // Here `idx` refers to the order of which the discriminant appears, and its index in `vs` - let report = |dis: Discr<'tcx>, - idx: usize, - err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>| { + let report = |dis: Discr<'tcx>, idx: usize, err: &mut Diagnostic| { let var = &vs[idx]; // HIR for the duplicate discriminant let (span, display_discr) = match var.disr_expr { Some(ref expr) => { diff --git a/compiler/rustc_typeck/src/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs index 540a8c3a83d..6c6bbfa22e3 100644 --- a/compiler/rustc_typeck/src/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -1479,6 +1479,10 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } Err(coercion_error) => { + // Mark that we've failed to coerce the types here to suppress + // any superfluous errors we might encounter while trying to + // emit or provide suggestions on how to fix the initial error. + fcx.set_tainted_by_errors(); let (expected, found) = if label_expression_as_expected { // In the case where this is a "forced unit", like // `break`, we want to call the `()` "expected" @@ -1581,9 +1585,9 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } } - fn note_unreachable_loop_return<'a>( + fn note_unreachable_loop_return( &self, - err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>, + err: &mut Diagnostic, expr: &hir::Expr<'tcx>, ret_exprs: &Vec<&'tcx hir::Expr<'tcx>>, ) { diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index 666498403c4..15a995ae59a 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -264,8 +264,13 @@ fn compare_predicate_entailment<'tcx>( let trait_sig = tcx.bound_fn_sig(trait_m.def_id).subst(tcx, trait_to_placeholder_substs); let trait_sig = tcx.liberate_late_bound_regions(impl_m.def_id, trait_sig); + // Next, add all inputs and output as well-formed tys. Importantly, + // we have to do this before normalization, since the normalized ty may + // not contain the input parameters. See issue #87748. + wf_tys.extend(trait_sig.inputs_and_output.iter()); let trait_sig = ocx.normalize(norm_cause, param_env, trait_sig); - // Add the resulting inputs and output as well-formed. + // We also have to add the normalized trait signature + // as we don't normalize during implied bounds computation. wf_tys.extend(trait_sig.inputs_and_output.iter()); let trait_fty = tcx.mk_fn_ptr(ty::Binder::dummy(trait_sig)); diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index 0595b9a73be..bac0be44aa9 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -598,13 +598,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let self_ty = self.typeck_results.borrow().expr_ty(&method_expr[0]); - let self_ty = format!("{:?}", self_ty); let name = method_path.ident.name; - let is_as_ref_able = (self_ty.starts_with("&std::option::Option") - || self_ty.starts_with("&std::result::Result") - || self_ty.starts_with("std::option::Option") - || self_ty.starts_with("std::result::Result")) - && (name == sym::map || name == sym::and_then); + let is_as_ref_able = match self_ty.peel_refs().kind() { + ty::Adt(def, _) => { + (self.tcx.is_diagnostic_item(sym::Option, def.did()) + || self.tcx.is_diagnostic_item(sym::Result, def.did())) + && (name == sym::map || name == sym::and_then) + } + _ => false, + }; match (is_as_ref_able, self.sess().source_map().span_to_snippet(method_path.ident.span)) { (true, Ok(src)) => { let suggestion = format!("as_ref().{}", src); @@ -792,7 +794,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ if is_range_literal(expr) => true, _ => false, }; - let sugg_expr = if needs_parens { format!("({src})") } else { src }; if let Some(sugg) = self.can_use_as_ref(expr) { return Some(( @@ -820,6 +821,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + let sugg_expr = if needs_parens { format!("({src})") } else { src }; return Some(match mutability { hir::Mutability::Mut => ( sp, diff --git a/compiler/rustc_typeck/src/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs index fb78632069e..6a6c03a8cba 100644 --- a/compiler/rustc_typeck/src/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -28,7 +28,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_errors::{ pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticId, - EmissionGuarantee, ErrorGuaranteed, + ErrorGuaranteed, }; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, Res}; @@ -879,7 +879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs: &'tcx hir::Expr<'tcx>, err_code: &'static str, op_span: Span, - adjust_err: impl FnOnce(&mut DiagnosticBuilder<'tcx, ErrorGuaranteed>), + adjust_err: impl FnOnce(&mut Diagnostic), ) { if lhs.is_syntactic_place_expr() { return; @@ -1089,8 +1089,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); - let suggest_deref_binop = |err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, - rhs_ty: Ty<'tcx>| { + let suggest_deref_binop = |err: &mut Diagnostic, rhs_ty: Ty<'tcx>| { if let Some(lhs_deref_ty) = self.deref_once_mutably_for_diagnostic(lhs_ty) { // Can only assign if the type is sized, so if `DerefMut` yields a type that is // unsized, do not suggest dereferencing it. @@ -2205,9 +2204,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx().ty_error() } - fn check_call_constructor<G: EmissionGuarantee>( + fn check_call_constructor( &self, - err: &mut DiagnosticBuilder<'_, G>, + err: &mut Diagnostic, base: &'tcx hir::Expr<'tcx>, def_id: DefId, ) { @@ -2526,15 +2525,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // try to add a suggestion in case the field is a nested field of a field of the Adt - if let Some((fields, substs)) = self.get_field_candidates(span, expr_t) { - for candidate_field in fields.iter() { + let mod_id = self.tcx.parent_module(id).to_def_id(); + if let Some((fields, substs)) = + self.get_field_candidates_considering_privacy(span, expr_t, mod_id) + { + for candidate_field in fields { if let Some(mut field_path) = self.check_for_nested_field_satisfying( span, &|candidate_field, _| candidate_field.ident(self.tcx()) == field, candidate_field, substs, vec![], - self.tcx.parent_module(id).to_def_id(), + mod_id, ) { // field_path includes `field` that we're looking for, so pop it. field_path.pop(); @@ -2558,22 +2560,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err } - pub(crate) fn get_field_candidates( + pub(crate) fn get_field_candidates_considering_privacy( &self, span: Span, - base_t: Ty<'tcx>, - ) -> Option<(&[ty::FieldDef], SubstsRef<'tcx>)> { - debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_t); + base_ty: Ty<'tcx>, + mod_id: DefId, + ) -> Option<(impl Iterator<Item = &'tcx ty::FieldDef> + 'tcx, SubstsRef<'tcx>)> { + debug!("get_field_candidates(span: {:?}, base_t: {:?}", span, base_ty); - for (base_t, _) in self.autoderef(span, base_t) { + for (base_t, _) in self.autoderef(span, base_ty) { match base_t.kind() { ty::Adt(base_def, substs) if !base_def.is_enum() => { + let tcx = self.tcx; let fields = &base_def.non_enum_variant().fields; - // For compile-time reasons put a limit on number of fields we search - if fields.len() > 100 { - return None; + // Some struct, e.g. some that impl `Deref`, have all private fields + // because you're expected to deref them to access the _real_ fields. + // This, for example, will help us suggest accessing a field through a `Box<T>`. + if fields.iter().all(|field| !field.vis.is_accessible_from(mod_id, tcx)) { + continue; } - return Some((fields, substs)); + return Some(( + fields + .iter() + .filter(move |field| field.vis.is_accessible_from(mod_id, tcx)) + // For compile-time reasons put a limit on number of fields we search + .take(100), + substs, + )); } _ => {} } @@ -2590,7 +2603,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidate_field: &ty::FieldDef, subst: SubstsRef<'tcx>, mut field_path: Vec<Ident>, - id: DefId, + mod_id: DefId, ) -> Option<Vec<Ident>> { debug!( "check_for_nested_field_satisfying(span: {:?}, candidate_field: {:?}, field_path: {:?}", @@ -2602,24 +2615,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // up to a depth of three None } else { - // recursively search fields of `candidate_field` if it's a ty::Adt field_path.push(candidate_field.ident(self.tcx).normalize_to_macros_2_0()); let field_ty = candidate_field.ty(self.tcx, subst); - if let Some((nested_fields, subst)) = self.get_field_candidates(span, field_ty) { - for field in nested_fields.iter() { - if field.vis.is_accessible_from(id, self.tcx) { - if matches(candidate_field, field_ty) { - return Some(field_path); - } else if let Some(field_path) = self.check_for_nested_field_satisfying( - span, - matches, - field, - subst, - field_path.clone(), - id, - ) { - return Some(field_path); - } + if matches(candidate_field, field_ty) { + return Some(field_path); + } else if let Some((nested_fields, subst)) = + self.get_field_candidates_considering_privacy(span, field_ty, mod_id) + { + // recursively search fields of `candidate_field` if it's a ty::Adt + for field in nested_fields { + if let Some(field_path) = self.check_for_nested_field_satisfying( + span, + matches, + field, + subst, + field_path.clone(), + mod_id, + ) { + return Some(field_path); } } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 660e7e4e399..1d1f755947f 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -1778,7 +1778,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn label_fn_like( &self, - err: &mut rustc_errors::DiagnosticBuilder<'tcx, rustc_errors::ErrorGuaranteed>, + err: &mut Diagnostic, callable_def_id: Option<DefId>, callee_ty: Option<Ty<'tcx>>, ) { diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs index 05bcc710e16..e008d50aa51 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/mod.rs @@ -26,6 +26,17 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode}; use std::cell::{Cell, RefCell}; use std::ops::Deref; +/// The `FnCtxt` stores type-checking context needed to type-check bodies of +/// functions, closures, and `const`s, including performing type inference +/// with [`InferCtxt`]. +/// +/// This is in contrast to [`ItemCtxt`], which is used to type-check item *signatures* +/// and thus does not perform type inference. +/// +/// See [`ItemCtxt`]'s docs for more. +/// +/// [`ItemCtxt`]: crate::collect::ItemCtxt +/// [`InferCtxt`]: infer::InferCtxt pub struct FnCtxt<'a, 'tcx> { pub(super) body_id: hir::HirId, diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index c92b93cbc22..44c7c148c75 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -904,7 +904,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let label_span_not_found = |err: &mut DiagnosticBuilder<'_, _>| { + let label_span_not_found = |err: &mut Diagnostic| { if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); let is_string_or_ref_str = match actual.kind() { @@ -1000,7 +1000,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { label_span_not_found(&mut err); } - self.check_for_field_method(&mut err, source, span, actual, item_name); + // Don't suggest (for example) `expr.field.method()` if `expr.method()` + // doesn't exist due to unsatisfied predicates. + if unsatisfied_predicates.is_empty() { + self.check_for_field_method(&mut err, source, span, actual, item_name); + } self.check_for_unwrap_self(&mut err, source, span, actual, item_name); @@ -1150,7 +1154,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rcvr_ty: Ty<'tcx>, expr: &hir::Expr<'_>, item_name: Ident, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut Diagnostic, ) -> bool { let tcx = self.tcx; let field_receiver = self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() { @@ -1327,17 +1331,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_for_field_method( &self, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut Diagnostic, source: SelfSource<'tcx>, span: Span, actual: Ty<'tcx>, item_name: Ident, ) { if let SelfSource::MethodCall(expr) = source - && let Some((fields, substs)) = self.get_field_candidates(span, actual) + && let mod_id = self.tcx.parent_module(expr.hir_id).to_def_id() + && let Some((fields, substs)) = self.get_field_candidates_considering_privacy(span, actual, mod_id) { let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)); - for candidate_field in fields.iter() { + for candidate_field in fields { if let Some(field_path) = self.check_for_nested_field_satisfying( span, &|_, field_ty| { @@ -1353,7 +1358,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidate_field, substs, vec![], - self.tcx.parent_module(expr.hir_id).to_def_id(), + mod_id, ) { let field_path_str = field_path .iter() @@ -1375,7 +1380,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn check_for_unwrap_self( &self, - err: &mut DiagnosticBuilder<'tcx, ErrorGuaranteed>, + err: &mut Diagnostic, source: SelfSource<'tcx>, span: Span, actual: Ty<'tcx>, diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index b73d9a9eb75..1b50209ee64 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -104,7 +104,7 @@ use crate::astconv::AstConv; use crate::check::gather_locals::GatherLocalsVisitor; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ - pluralize, struct_span_err, Applicability, DiagnosticBuilder, EmissionGuarantee, MultiSpan, + pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, MultiSpan, }; use rustc_hir as hir; use rustc_hir::def::Res; @@ -973,12 +973,7 @@ fn has_expected_num_generic_args<'tcx>( /// * `span` - The span of the snippet /// * `params` - The number of parameters the constructor accepts /// * `err` - A mutable diagnostic builder to add the suggestion to -fn suggest_call_constructor<G: EmissionGuarantee>( - span: Span, - kind: CtorOf, - params: usize, - err: &mut DiagnosticBuilder<'_, G>, -) { +fn suggest_call_constructor(span: Span, kind: CtorOf, params: usize, err: &mut Diagnostic) { // Note: tuple-structs don't have named fields, so just use placeholders let args = vec!["_"; params].join(", "); let applicable = if params > 0 { diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 920b3e68808..eb0c51bb2f9 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -59,7 +59,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { // Suppress this error, since we already emitted // a deref suggestion in check_overloaded_binop - err.delay_as_bug(); + err.downgrade_to_delayed_bug(); } } }); diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 99996e80c9c..e7c5ecc60ec 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -94,7 +94,27 @@ pub fn provide(providers: &mut Providers) { /////////////////////////////////////////////////////////////////////////// /// Context specific to some particular item. This is what implements -/// `AstConv`. It has information about the predicates that are defined +/// [`AstConv`]. +/// +/// # `ItemCtxt` vs `FnCtxt` +/// +/// `ItemCtxt` is primarily used to type-check item signatures and lower them +/// from HIR to their [`ty::Ty`] representation, which is exposed using [`AstConv`]. +/// It's also used for the bodies of items like structs where the body (the fields) +/// are just signatures. +/// +/// This is in contrast to [`FnCtxt`], which is used to type-check bodies of +/// functions, closures, and `const`s -- anywhere that expressions and statements show up. +/// +/// An important thing to note is that `ItemCtxt` does no inference -- it has no [`InferCtxt`] -- +/// while `FnCtxt` does do inference. +/// +/// [`FnCtxt`]: crate::check::FnCtxt +/// [`InferCtxt`]: rustc_infer::infer::InferCtxt +/// +/// # Trait predicates +/// +/// `ItemCtxt` has information about the predicates that are defined /// on the trait. Unfortunately, this predicate information is /// available in various different forms at various points in the /// process. So we can't just store a pointer to e.g., the AST or the diff --git a/library/core/benches/num/int_log/mod.rs b/library/core/benches/num/int_log/mod.rs index 19864d2d467..3c01e2998cd 100644 --- a/library/core/benches/num/int_log/mod.rs +++ b/library/core/benches/num/int_log/mod.rs @@ -9,7 +9,7 @@ macro_rules! int_log_bench { for n in 0..(<$t>::BITS / 8) { for i in 1..=(100 as $t) { let x = black_box(i << (n * 8)); - black_box(x.log10()); + black_box(x.ilog10()); } } }); @@ -27,7 +27,7 @@ macro_rules! int_log_bench { .collect(); bench.iter(|| { for x in &numbers { - black_box(black_box(x).log10()); + black_box(black_box(x).ilog10()); } }); } @@ -44,7 +44,7 @@ macro_rules! int_log_bench { .collect(); bench.iter(|| { for x in &numbers { - black_box(black_box(x).log10()); + black_box(black_box(x).ilog10()); } }); } diff --git a/library/core/src/alloc/global.rs b/library/core/src/alloc/global.rs index 887246c6001..6756eecd0e0 100644 --- a/library/core/src/alloc/global.rs +++ b/library/core/src/alloc/global.rs @@ -74,7 +74,7 @@ use crate::ptr; /// { /// return null_mut(); /// }; -/// (self.arena.get() as *mut u8).add(allocated) +/// self.arena.get().cast::<u8>().add(allocated) /// } /// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} /// } diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 59ebe5fbe02..3473ac09e95 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -72,9 +72,8 @@ impl Layout { Layout::from_size_valid_align(size, unsafe { ValidAlign::new_unchecked(align) }) } - /// Internal helper constructor to skip revalidating alignment validity. - #[inline] - const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> { + #[inline(always)] + const fn max_size_for_align(align: ValidAlign) -> usize { // (power-of-two implies align != 0.) // Rounded up size is: @@ -89,7 +88,13 @@ impl Layout { // // Above implies that checking for summation overflow is both // necessary and sufficient. - if size > isize::MAX as usize - (align.as_nonzero().get() - 1) { + isize::MAX as usize - (align.as_usize() - 1) + } + + /// Internal helper constructor to skip revalidating alignment validity. + #[inline] + const fn from_size_valid_align(size: usize, align: ValidAlign) -> Result<Self, LayoutError> { + if size > Self::max_size_for_align(align) { return Err(LayoutError); } @@ -128,7 +133,7 @@ impl Layout { without modifying the layout"] #[inline] pub const fn align(&self) -> usize { - self.align.as_nonzero().get() + self.align.as_usize() } /// Constructs a `Layout` suitable for holding a value of type `T`. @@ -410,13 +415,33 @@ impl Layout { /// Creates a layout describing the record for a `[T; n]`. /// - /// On arithmetic overflow, returns `LayoutError`. + /// On arithmetic overflow or when the total size would exceed + /// `isize::MAX`, returns `LayoutError`. #[stable(feature = "alloc_layout_manipulation", since = "1.44.0")] #[inline] pub fn array<T>(n: usize) -> Result<Self, LayoutError> { - let array_size = mem::size_of::<T>().checked_mul(n).ok_or(LayoutError)?; - // The safe constructor is called here to enforce the isize size limit. - Layout::from_size_valid_align(array_size, ValidAlign::of::<T>()) + // Reduce the amount of code we need to monomorphize per `T`. + return inner(mem::size_of::<T>(), ValidAlign::of::<T>(), n); + + #[inline] + fn inner(element_size: usize, align: ValidAlign, n: usize) -> Result<Layout, LayoutError> { + // We need to check two things about the size: + // - That the total size won't overflow a `usize`, and + // - That the total size still fits in an `isize`. + // By using division we can check them both with a single threshold. + // That'd usually be a bad idea, but thankfully here the element size + // and alignment are constants, so the compiler will fold all of it. + if element_size != 0 && n > Layout::max_size_for_align(align) / element_size { + return Err(LayoutError); + } + + let array_size = element_size * n; + + // SAFETY: We just checked above that the `array_size` will not + // exceed `isize::MAX` even when rounded up to the alignment. + // And `ValidAlign` guarantees it's a power of two. + unsafe { Ok(Layout::from_size_align_unchecked(array_size, align.as_usize())) } + } } } diff --git a/library/core/src/array/equality.rs b/library/core/src/array/equality.rs index 33f7f494e9d..b2c895f882c 100644 --- a/library/core/src/array/equality.rs +++ b/library/core/src/array/equality.rs @@ -173,13 +173,14 @@ macro_rules! is_raw_eq_comparable { )+}; } -// SAFETY: All the ordinary integer types allow all bit patterns as distinct values +// SAFETY: All the ordinary integer types have no padding, and are not pointers. is_raw_eq_comparable!(u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize); -// SAFETY: bool and char have *niches*, but no *padding*, so this is sound +// SAFETY: bool and char have *niches*, but no *padding* (and these are not pointer types), so this +// is sound is_raw_eq_comparable!(bool, char); -// SAFETY: Similarly, the non-zero types have a niche, but no undef, +// SAFETY: Similarly, the non-zero types have a niche, but no undef and no pointers, // and they compare like their underlying numeric type. is_raw_eq_comparable!( NonZeroU8, diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index eae567cad00..2433139a592 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -892,8 +892,7 @@ impl char { /// /// The general categories for numbers (`Nd` for decimal digits, `Nl` for letter-like numeric /// characters, and `No` for other numeric characters) are specified in the [Unicode Character - /// Database][ucd] [`UnicodeData.txt`]. Note that this means ideographic numbers like '三' - /// are considered alphabetic, not numeric. Please consider to use `is_ascii_digit` or `is_digit`. + /// Database][ucd] [`UnicodeData.txt`]. /// /// This method doesn't cover everything that could be considered a number, e.g. ideographic numbers like '三'. /// If you want everything including characters with overlapping purposes then you might want to use diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 82e63a7fe1d..d8b8ac4d871 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -387,6 +387,7 @@ impl CStr { #[rustc_const_stable(feature = "const_cstr_unchecked", since = "1.59.0")] #[rustc_allow_const_fn_unstable(const_eval_select)] pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr { + #[inline] fn rt_impl(bytes: &[u8]) -> &CStr { // Chance at catching some UB at runtime with debug builds. debug_assert!(!bytes.is_empty() && bytes[bytes.len() - 1] == 0); diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index cabc5017f1d..2d44feb15f8 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -2282,7 +2282,8 @@ extern "rust-intrinsic" { /// /// # Safety /// - /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized. + /// It's UB to call this if any of the *bytes* in `*a` or `*b` are uninitialized or carry a + /// pointer value. /// Note that this is a stricter criterion than just the *values* being /// fully-initialized: if `T` has padding, it's UB to call this intrinsic. /// diff --git a/library/core/src/mem/valid_align.rs b/library/core/src/mem/valid_align.rs index 4ce6d13cf90..b9ccc0b4c79 100644 --- a/library/core/src/mem/valid_align.rs +++ b/library/core/src/mem/valid_align.rs @@ -36,9 +36,14 @@ impl ValidAlign { } #[inline] + pub(crate) const fn as_usize(self) -> usize { + self.0 as usize + } + + #[inline] pub(crate) const fn as_nonzero(self) -> NonZeroUsize { // SAFETY: All the discriminants are non-zero. - unsafe { NonZeroUsize::new_unchecked(self.0 as usize) } + unsafe { NonZeroUsize::new_unchecked(self.as_usize()) } } /// Returns the base 2 logarithm of the alignment. diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index de85fdd6ed2..d2a21b6b382 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -137,7 +137,7 @@ macro_rules! define_bignum { // Find the most significant non-zero digit. let msd = digits.iter().rposition(|&x| x != 0); match msd { - Some(msd) => msd * digitbits + digits[msd].log2() as usize + 1, + Some(msd) => msd * digitbits + digits[msd].ilog2() as usize + 1, // There are no non-zero digits, i.e., the number is zero. _ => 0, } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index a66de19bad0..92b12ed3352 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2204,7 +2204,7 @@ macro_rules! int_impl { /// rounded down. /// /// This method might not be optimized owing to implementation details; - /// `log2` can produce results more efficiently for base 2, and `log10` + /// `ilog2` can produce results more efficiently for base 2, and `ilog10` /// can produce results more efficiently for base 10. /// /// # Panics @@ -2217,7 +2217,7 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -2226,8 +2226,8 @@ macro_rules! int_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log(self, base: Self) -> u32 { - match self.checked_log(base) { + pub const fn ilog(self, base: Self) -> u32 { + match self.checked_ilog(base) { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -2250,7 +2250,7 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -2259,8 +2259,8 @@ macro_rules! int_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log2(self) -> u32 { - match self.checked_log2() { + pub const fn ilog2(self) -> u32 { + match self.checked_ilog2() { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -2283,7 +2283,7 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -2292,8 +2292,8 @@ macro_rules! int_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log10(self) -> u32 { - match self.checked_log10() { + pub const fn ilog10(self) -> u32 { + match self.checked_ilog10() { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -2311,20 +2311,20 @@ macro_rules! int_impl { /// Returns `None` if the number is negative or zero, or if the base is not at least 2. /// /// This method might not be optimized owing to implementation details; - /// `checked_log2` can produce results more efficiently for base 2, and - /// `checked_log10` can produce results more efficiently for base 10. + /// `checked_ilog2` can produce results more efficiently for base 2, and + /// `checked_ilog10` can produce results more efficiently for base 10. /// /// # Examples /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log(self, base: Self) -> Option<u32> { + pub const fn checked_ilog(self, base: Self) -> Option<u32> { if self <= 0 || base <= 1 { None } else { @@ -2333,7 +2333,7 @@ macro_rules! int_impl { // Optimization for 128 bit wide integers. if Self::BITS == 128 { - let b = Self::log2(self) / (Self::log2(base) + 1); + let b = Self::ilog2(self) / (Self::ilog2(base) + 1); n += b; r /= base.pow(b as u32); } @@ -2354,13 +2354,13 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log2(self) -> Option<u32> { + pub const fn checked_ilog2(self) -> Option<u32> { if self <= 0 { None } else { @@ -2378,13 +2378,13 @@ macro_rules! int_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log10(self) -> Option<u32> { + pub const fn checked_ilog10(self) -> Option<u32> { if self > 0 { Some(int_log10::$ActualT(self as $ActualT)) } else { diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 4de0a0cf564..6196c4da4e3 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -450,7 +450,7 @@ macro_rules! nonzero_unsigned_operations { /// Returns the base 2 logarithm of the number, rounded down. /// /// This is the same operation as - #[doc = concat!("[`", stringify!($Int), "::log2`],")] + #[doc = concat!("[`", stringify!($Int), "::ilog2`],")] /// except that it has no failure cases to worry about /// since this value can never be zero. /// @@ -460,22 +460,22 @@ macro_rules! nonzero_unsigned_operations { /// #![feature(int_log)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().log2(), 2);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().log2(), 3);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().log2(), 3);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(7).unwrap().ilog2(), 2);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(8).unwrap().ilog2(), 3);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(9).unwrap().ilog2(), 3);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn log2(self) -> u32 { + pub const fn ilog2(self) -> u32 { Self::BITS - 1 - self.leading_zeros() } /// Returns the base 10 logarithm of the number, rounded down. /// /// This is the same operation as - #[doc = concat!("[`", stringify!($Int), "::log10`],")] + #[doc = concat!("[`", stringify!($Int), "::ilog10`],")] /// except that it has no failure cases to worry about /// since this value can never be zero. /// @@ -485,15 +485,15 @@ macro_rules! nonzero_unsigned_operations { /// #![feature(int_log)] #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().log10(), 1);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().log10(), 2);")] - #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().log10(), 2);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(99).unwrap().ilog10(), 1);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(100).unwrap().ilog10(), 2);")] + #[doc = concat!("assert_eq!(", stringify!($Ty), "::new(101).unwrap().ilog10(), 2);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn log10(self) -> u32 { + pub const fn ilog10(self) -> u32 { super::int_log10::$Int(self.0) } } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 73365544233..aa3e8b9974e 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -700,7 +700,7 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".log(5), 1);")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".ilog(5), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -709,8 +709,8 @@ macro_rules! uint_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log(self, base: Self) -> u32 { - match self.checked_log(base) { + pub const fn ilog(self, base: Self) -> u32 { + match self.checked_ilog(base) { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -733,7 +733,7 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".log2(), 1);")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".ilog2(), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -742,8 +742,8 @@ macro_rules! uint_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log2(self) -> u32 { - match self.checked_log2() { + pub const fn ilog2(self) -> u32 { + match self.checked_ilog2() { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -766,7 +766,7 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".log10(), 1);")] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".ilog10(), 1);")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ @@ -775,8 +775,8 @@ macro_rules! uint_impl { #[track_caller] #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] - pub const fn log10(self) -> u32 { - match self.checked_log10() { + pub const fn ilog10(self) -> u32 { + match self.checked_ilog10() { Some(n) => n, None => { // In debug builds, trigger a panic on None. @@ -794,20 +794,20 @@ macro_rules! uint_impl { /// Returns `None` if the number is zero, or if the base is not at least 2. /// /// This method might not be optimized owing to implementation details; - /// `checked_log2` can produce results more efficiently for base 2, and - /// `checked_log10` can produce results more efficiently for base 10. + /// `checked_ilog2` can produce results more efficiently for base 2, and + /// `checked_ilog10` can produce results more efficiently for base 10. /// /// # Examples /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_log(5), Some(1));")] + #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".checked_ilog(5), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log(self, base: Self) -> Option<u32> { + pub const fn checked_ilog(self, base: Self) -> Option<u32> { if self <= 0 || base <= 1 { None } else { @@ -816,7 +816,7 @@ macro_rules! uint_impl { // Optimization for 128 bit wide integers. if Self::BITS == 128 { - let b = Self::log2(self) / (Self::log2(base) + 1); + let b = Self::ilog2(self) / (Self::ilog2(base) + 1); n += b; r /= base.pow(b as u32); } @@ -837,15 +837,15 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_log2(), Some(1));")] + #[doc = concat!("assert_eq!(2", stringify!($SelfT), ".checked_ilog2(), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log2(self) -> Option<u32> { + pub const fn checked_ilog2(self) -> Option<u32> { if let Some(x) = <$NonZeroT>::new(self) { - Some(x.log2()) + Some(x.ilog2()) } else { None } @@ -859,15 +859,15 @@ macro_rules! uint_impl { /// /// ``` /// #![feature(int_log)] - #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_log10(), Some(1));")] + #[doc = concat!("assert_eq!(10", stringify!($SelfT), ".checked_ilog10(), Some(1));")] /// ``` #[unstable(feature = "int_log", issue = "70887")] #[must_use = "this returns the result of the operation, \ without modifying the original"] #[inline] - pub const fn checked_log10(self) -> Option<u32> { + pub const fn checked_ilog10(self) -> Option<u32> { if let Some(x) = <$NonZeroT>::new(self) { - Some(x.log10()) + Some(x.ilog10()) } else { None } diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 2cd6e23c71a..c25b159c533 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -95,8 +95,8 @@ impl<T: ?Sized> *const T { /// /// This is a bit safer than `as` because it wouldn't silently change the type if the code is /// refactored. - #[unstable(feature = "ptr_const_cast", issue = "92675")] - #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")] + #[stable(feature = "ptr_const_cast", since = "1.65.0")] + #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] pub const fn cast_mut(self) -> *mut T { self as _ } @@ -1267,20 +1267,21 @@ impl<T: ?Sized> *const T { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// # fn foo(n: usize) { - /// # use std::mem::align_of; + /// use std::mem::align_of; + /// /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = x.as_ptr().add(n) as *const u8; + /// let x = [5_u8, 6, 7, 8, 9]; + /// let ptr = x.as_ptr(); /// let offset = ptr.align_offset(align_of::<u16>()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); + /// + /// if offset < x.len() - 1 { + /// let u16_ptr = ptr.add(offset).cast::<u16>(); + /// assert!(*u16_ptr == u16::from_ne_bytes([5, 6]) || *u16_ptr == u16::from_ne_bytes([6, 7])); /// } else { /// // while the pointer can be aligned via `offset`, it would point /// // outside the allocation /// } - /// # } } + /// # } /// ``` #[stable(feature = "align_offset", since = "1.36.0")] #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 56ad5f7658e..fff06b458c7 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -100,8 +100,8 @@ impl<T: ?Sized> *mut T { /// coercion. /// /// [`cast_mut`]: #method.cast_mut - #[unstable(feature = "ptr_const_cast", issue = "92675")] - #[rustc_const_unstable(feature = "ptr_const_cast", issue = "92675")] + #[stable(feature = "ptr_const_cast", since = "1.65.0")] + #[rustc_const_stable(feature = "ptr_const_cast", since = "1.65.0")] pub const fn cast_const(self) -> *const T { self as _ } @@ -1545,20 +1545,23 @@ impl<T: ?Sized> *mut T { /// Accessing adjacent `u8` as `u16` /// /// ``` - /// # fn foo(n: usize) { - /// # use std::mem::align_of; + /// use std::mem::align_of; + /// /// # unsafe { - /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = x.as_ptr().add(n) as *const u8; + /// let mut x = [5_u8, 6, 7, 8, 9]; + /// let ptr = x.as_mut_ptr(); /// let offset = ptr.align_offset(align_of::<u16>()); - /// if offset < x.len() - n - 1 { - /// let u16_ptr = ptr.add(offset) as *const u16; - /// assert_ne!(*u16_ptr, 500); + /// + /// if offset < x.len() - 1 { + /// let u16_ptr = ptr.add(offset).cast::<u16>(); + /// *u16_ptr = 0; + /// + /// assert!(x == [0, 0, 7, 8, 9] || x == [5, 0, 0, 8, 9]); /// } else { /// // while the pointer can be aligned via `offset`, it would point /// // outside the allocation /// } - /// # } } + /// # } /// ``` #[stable(feature = "align_offset", since = "1.36.0")] #[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index f1e65930967..f43b780ec9a 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -92,7 +92,7 @@ impl<'a, T> Iter<'a, T> { assume(!ptr.is_null()); let end = if mem::size_of::<T>() == 0 { - (ptr as *const u8).wrapping_add(slice.len()) as *const T + ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) }; @@ -228,7 +228,7 @@ impl<'a, T> IterMut<'a, T> { assume(!ptr.is_null()); let end = if mem::size_of::<T>() == 0 { - (ptr as *mut u8).wrapping_add(slice.len()) as *mut T + ptr.wrapping_byte_add(slice.len()) } else { ptr.add(slice.len()) }; diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 48353756741..153dc4dbb08 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -321,8 +321,8 @@ impl Duration { /// To determine the total number of seconds represented by the `Duration` /// including the fractional part, use [`as_secs_f64`] or [`as_secs_f32`] /// - /// [`as_secs_f32`]: Duration::as_secs_f64 - /// [`as_secs_f64`]: Duration::as_secs_f32 + /// [`as_secs_f64`]: Duration::as_secs_f64 + /// [`as_secs_f32`]: Duration::as_secs_f32 /// [`subsec_nanos`]: Duration::subsec_nanos #[stable(feature = "duration", since = "1.3.0")] #[rustc_const_stable(feature = "duration_consts", since = "1.32.0")] @@ -1135,7 +1135,7 @@ impl fmt::Debug for Duration { // 2. The postfix: can be "µs" so we have to count UTF8 characters. let mut actual_w = prefix.len() + postfix.chars().count(); // 3. The integer part: - if let Some(log) = integer_part.checked_log10() { + if let Some(log) = integer_part.checked_ilog10() { // integer_part is > 0, so has length log10(x)+1 actual_w += 1 + log as usize; } else { diff --git a/library/core/tests/alloc.rs b/library/core/tests/alloc.rs index 8a5a06b3440..3ceaeadcec6 100644 --- a/library/core/tests/alloc.rs +++ b/library/core/tests/alloc.rs @@ -1,4 +1,5 @@ use core::alloc::Layout; +use core::mem::size_of; use core::ptr::{self, NonNull}; #[test] @@ -13,6 +14,49 @@ fn const_unchecked_layout() { } #[test] +fn layout_round_up_to_align_edge_cases() { + const MAX_SIZE: usize = isize::MAX as usize; + + for shift in 0..usize::BITS { + let align = 1_usize << shift; + let edge = (MAX_SIZE + 1) - align; + let low = edge.saturating_sub(10); + let high = edge.saturating_add(10); + assert!(Layout::from_size_align(low, align).is_ok()); + assert!(Layout::from_size_align(high, align).is_err()); + for size in low..=high { + assert_eq!( + Layout::from_size_align(size, align).is_ok(), + size.next_multiple_of(align) <= MAX_SIZE, + ); + } + } +} + +#[test] +fn layout_array_edge_cases() { + for_type::<i64>(); + for_type::<[i32; 0b10101]>(); + for_type::<[u8; 0b1010101]>(); + + // Make sure ZSTs don't lead to divide-by-zero + assert_eq!(Layout::array::<()>(usize::MAX).unwrap(), Layout::from_size_align(0, 1).unwrap()); + + fn for_type<T>() { + const MAX_SIZE: usize = isize::MAX as usize; + + let edge = (MAX_SIZE + 1) / size_of::<T>(); + let low = edge.saturating_sub(10); + let high = edge.saturating_add(10); + assert!(Layout::array::<T>(low).is_ok()); + assert!(Layout::array::<T>(high).is_err()); + for n in low..=high { + assert_eq!(Layout::array::<T>(n).is_ok(), n * size_of::<T>() <= MAX_SIZE); + } + } +} + +#[test] fn layout_debug_shows_log2_of_alignment() { // `Debug` is not stable, but here's what it does right now let layout = Layout::from_size_align(24576, 8192).unwrap(); diff --git a/library/core/tests/const_ptr.rs b/library/core/tests/const_ptr.rs index 152fed803ec..d874f08317f 100644 --- a/library/core/tests/const_ptr.rs +++ b/library/core/tests/const_ptr.rs @@ -3,7 +3,7 @@ const DATA: [u16; 2] = [u16::from_ne_bytes([0x01, 0x23]), u16::from_ne_bytes([0x const fn unaligned_ptr() -> *const u16 { // Since DATA.as_ptr() is aligned to two bytes, adding 1 byte to that produces an unaligned *const u16 - unsafe { (DATA.as_ptr() as *const u8).add(1) as *const u16 } + unsafe { DATA.as_ptr().byte_add(1) } } #[test] @@ -67,7 +67,7 @@ fn write() { const fn write_unaligned() -> [u16; 2] { let mut two_aligned = [0u16; 2]; unsafe { - let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; + let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); ptr::write_unaligned(unaligned_ptr, u16::from_ne_bytes([0x23, 0x45])); } two_aligned @@ -91,7 +91,7 @@ fn mut_ptr_write() { const fn write_unaligned() -> [u16; 2] { let mut two_aligned = [0u16; 2]; unsafe { - let unaligned_ptr = (two_aligned.as_mut_ptr() as *mut u8).add(1) as *mut u16; + let unaligned_ptr = two_aligned.as_mut_ptr().byte_add(1); unaligned_ptr.write_unaligned(u16::from_ne_bytes([0x23, 0x45])); } two_aligned diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index db94368f6e0..df9b1073a09 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -14,6 +14,7 @@ #![feature(const_maybe_uninit_assume_init_read)] #![feature(const_nonnull_new)] #![feature(const_num_from_num)] +#![feature(const_pointer_byte_offsets)] #![feature(const_ptr_as_ref)] #![feature(const_ptr_read)] #![feature(const_ptr_write)] @@ -74,6 +75,7 @@ #![feature(never_type)] #![feature(unwrap_infallible)] #![feature(result_into_ok_or_err)] +#![feature(pointer_byte_offsets)] #![feature(portable_simd)] #![feature(ptr_metadata)] #![feature(once_cell)] diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs index dc3092e1486..be203fb5c04 100644 --- a/library/core/tests/num/int_log.rs +++ b/library/core/tests/num/int_log.rs @@ -1,166 +1,166 @@ -//! This tests the `Integer::{log,log2,log10}` methods. These tests are in a +//! This tests the `Integer::{ilog,log2,log10}` methods. These tests are in a //! separate file because there's both a large number of them, and not all tests -//! can be run on Android. This is because in Android `log2` uses an imprecise +//! can be run on Android. This is because in Android `ilog2` uses an imprecise //! approximation:https://github.com/rust-lang/rust/blob/4825e12fc9c79954aa0fe18f5521efa6c19c7539/src/libstd/sys/unix/android.rs#L27-L53 #[test] -fn checked_log() { - assert_eq!(999u32.checked_log(10), Some(2)); - assert_eq!(1000u32.checked_log(10), Some(3)); - assert_eq!(555u32.checked_log(13), Some(2)); - assert_eq!(63u32.checked_log(4), Some(2)); - assert_eq!(64u32.checked_log(4), Some(3)); - assert_eq!(10460353203u64.checked_log(3), Some(21)); - assert_eq!(10460353202u64.checked_log(3), Some(20)); - assert_eq!(147808829414345923316083210206383297601u128.checked_log(3), Some(80)); - assert_eq!(147808829414345923316083210206383297600u128.checked_log(3), Some(79)); - assert_eq!(22528399544939174411840147874772641u128.checked_log(19683), Some(8)); - assert_eq!(22528399544939174411840147874772631i128.checked_log(19683), Some(7)); - - assert_eq!(0u8.checked_log(4), None); - assert_eq!(0u16.checked_log(4), None); - assert_eq!(0i8.checked_log(4), None); - assert_eq!(0i16.checked_log(4), None); +fn checked_ilog() { + assert_eq!(999u32.checked_ilog(10), Some(2)); + assert_eq!(1000u32.checked_ilog(10), Some(3)); + assert_eq!(555u32.checked_ilog(13), Some(2)); + assert_eq!(63u32.checked_ilog(4), Some(2)); + assert_eq!(64u32.checked_ilog(4), Some(3)); + assert_eq!(10460353203u64.checked_ilog(3), Some(21)); + assert_eq!(10460353202u64.checked_ilog(3), Some(20)); + assert_eq!(147808829414345923316083210206383297601u128.checked_ilog(3), Some(80)); + assert_eq!(147808829414345923316083210206383297600u128.checked_ilog(3), Some(79)); + assert_eq!(22528399544939174411840147874772641u128.checked_ilog(19683), Some(8)); + assert_eq!(22528399544939174411840147874772631i128.checked_ilog(19683), Some(7)); + + assert_eq!(0u8.checked_ilog(4), None); + assert_eq!(0u16.checked_ilog(4), None); + assert_eq!(0i8.checked_ilog(4), None); + assert_eq!(0i16.checked_ilog(4), None); #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { - assert_eq!(i.checked_log(4), None); + assert_eq!(i.checked_ilog(4), None); } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32)); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32)); } } #[test] -fn checked_log2() { - assert_eq!(5u32.checked_log2(), Some(2)); - assert_eq!(0u64.checked_log2(), None); - assert_eq!(128i32.checked_log2(), Some(7)); - assert_eq!((-55i16).checked_log2(), None); +fn checked_ilog2() { + assert_eq!(5u32.checked_ilog2(), Some(2)); + assert_eq!(0u64.checked_ilog2(), None); + assert_eq!(128i32.checked_ilog2(), Some(7)); + assert_eq!((-55i16).checked_ilog2(), None); - assert_eq!(0u8.checked_log2(), None); - assert_eq!(0u16.checked_log2(), None); - assert_eq!(0i8.checked_log2(), None); - assert_eq!(0i16.checked_log2(), None); + assert_eq!(0u8.checked_ilog2(), None); + assert_eq!(0u16.checked_ilog2(), None); + assert_eq!(0i8.checked_ilog2(), None); + assert_eq!(0i16.checked_ilog2(), None); for i in 1..=u8::MAX { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - // Guard against Android's imprecise f32::log2 implementation. + // Guard against Android's imprecise f32::ilog2 implementation. if i != 8192 && i != 32768 { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); } } for i in i8::MIN..=0 { - assert_eq!(i.checked_log2(), None); + assert_eq!(i.checked_ilog2(), None); } for i in 1..=i8::MAX { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); } #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { - assert_eq!(i.checked_log2(), None); + assert_eq!(i.checked_ilog2(), None); } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - // Guard against Android's imprecise f32::log2 implementation. + // Guard against Android's imprecise f32::ilog2 implementation. if i != 8192 { - assert_eq!(i.checked_log2(), Some((i as f32).log2() as u32)); + assert_eq!(i.checked_ilog2(), Some((i as f32).log2() as u32)); } } } -// Validate cases that fail on Android's imprecise float log2 implementation. +// Validate cases that fail on Android's imprecise float ilog2 implementation. #[test] #[cfg(not(target_os = "android"))] -fn checked_log2_not_android() { - assert_eq!(8192u16.checked_log2(), Some((8192f32).log2() as u32)); - assert_eq!(32768u16.checked_log2(), Some((32768f32).log2() as u32)); - assert_eq!(8192i16.checked_log2(), Some((8192f32).log2() as u32)); +fn checked_ilog2_not_android() { + assert_eq!(8192u16.checked_ilog2(), Some((8192f32).log2() as u32)); + assert_eq!(32768u16.checked_ilog2(), Some((32768f32).log2() as u32)); + assert_eq!(8192i16.checked_ilog2(), Some((8192f32).log2() as u32)); } #[test] -fn checked_log10() { - assert_eq!(0u8.checked_log10(), None); - assert_eq!(0u16.checked_log10(), None); - assert_eq!(0i8.checked_log10(), None); - assert_eq!(0i16.checked_log10(), None); +fn checked_ilog10() { + assert_eq!(0u8.checked_ilog10(), None); + assert_eq!(0u16.checked_ilog10(), None); + assert_eq!(0i8.checked_ilog10(), None); + assert_eq!(0i16.checked_ilog10(), None); #[cfg(not(miri))] // Miri is too slow for i in i16::MIN..=0 { - assert_eq!(i.checked_log10(), None); + assert_eq!(i.checked_ilog10(), None); } #[cfg(not(miri))] // Miri is too slow for i in 1..=i16::MAX { - assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32)); + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32)); } #[cfg(not(miri))] // Miri is too slow for i in 1..=u16::MAX { - assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32)); + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32)); } #[cfg(not(miri))] // Miri is too slow for i in 1..=100_000u32 { - assert_eq!(i.checked_log10(), Some((i as f32).log10() as u32)); + assert_eq!(i.checked_ilog10(), Some((i as f32).log10() as u32)); } } -macro_rules! log10_loop { - ($T:ty, $log10_max:expr) => { - assert_eq!(<$T>::MAX.log10(), $log10_max); - for i in 0..=$log10_max { +macro_rules! ilog10_loop { + ($T:ty, $ilog10_max:expr) => { + assert_eq!(<$T>::MAX.ilog10(), $ilog10_max); + for i in 0..=$ilog10_max { let p = (10 as $T).pow(i as u32); if p >= 10 { - assert_eq!((p - 9).log10(), i - 1); - assert_eq!((p - 1).log10(), i - 1); + assert_eq!((p - 9).ilog10(), i - 1); + assert_eq!((p - 1).ilog10(), i - 1); } - assert_eq!(p.log10(), i); - assert_eq!((p + 1).log10(), i); + assert_eq!(p.ilog10(), i); + assert_eq!((p + 1).ilog10(), i); if p >= 10 { - assert_eq!((p + 9).log10(), i); + assert_eq!((p + 9).ilog10(), i); } - // also check `x.log(10)` + // also check `x.ilog(10)` if p >= 10 { - assert_eq!((p - 9).log(10), i - 1); - assert_eq!((p - 1).log(10), i - 1); + assert_eq!((p - 9).ilog(10), i - 1); + assert_eq!((p - 1).ilog(10), i - 1); } - assert_eq!(p.log(10), i); - assert_eq!((p + 1).log(10), i); + assert_eq!(p.ilog(10), i); + assert_eq!((p + 1).ilog(10), i); if p >= 10 { - assert_eq!((p + 9).log(10), i); + assert_eq!((p + 9).ilog(10), i); } } }; } #[test] -fn log10_u8() { - log10_loop! { u8, 2 } +fn ilog10_u8() { + ilog10_loop! { u8, 2 } } #[test] -fn log10_u16() { - log10_loop! { u16, 4 } +fn ilog10_u16() { + ilog10_loop! { u16, 4 } } #[test] -fn log10_u32() { - log10_loop! { u32, 9 } +fn ilog10_u32() { + ilog10_loop! { u32, 9 } } #[test] -fn log10_u64() { - log10_loop! { u64, 19 } +fn ilog10_u64() { + ilog10_loop! { u64, 19 } } #[test] -fn log10_u128() { - log10_loop! { u128, 38 } +fn ilog10_u128() { + ilog10_loop! { u128, 38 } } diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 0656109e9db..b8f6fe6961a 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1197,7 +1197,6 @@ fn chunks_mut_are_send_and_sync() { use std::slice::{ChunksExactMut, ChunksMut, RChunksExactMut, RChunksMut}; use std::sync::MutexGuard; - #[allow(unused)] fn assert_send_and_sync() where ChunksMut<'static, Cell<i32>>: Send, @@ -1210,6 +1209,8 @@ fn chunks_mut_are_send_and_sync() { RChunksExactMut<'static, MutexGuard<'static, u32>>: Sync, { } + + assert_send_and_sync(); } #[test] diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 05e9b2eb6bc..5cf6ec81789 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -9,12 +9,6 @@ //! implementing `std::error::Error`) to get a causal chain of where an error //! was generated. //! -//! > **Note**: this module is unstable and is designed in [RFC 2504], and you -//! > can learn more about its status in the [tracking issue]. -//! -//! [RFC 2504]: https://github.com/rust-lang/rfcs/blob/master/text/2504-fix-error.md -//! [tracking issue]: https://github.com/rust-lang/rust/issues/53487 -//! //! ## Accuracy //! //! Backtraces are attempted to be as accurate as possible, but no guarantees @@ -64,7 +58,7 @@ //! `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` at runtime might not actually change //! how backtraces are captured. -#![unstable(feature = "backtrace", issue = "53487")] +#![stable(feature = "backtrace", since = "1.65.0")] #[cfg(test)] mod tests; @@ -110,6 +104,7 @@ use crate::vec::Vec; /// previous point in time. In some instances the `Backtrace` type may /// internally be empty due to configuration. For more information see /// `Backtrace::capture`. +#[stable(feature = "backtrace", since = "1.65.0")] #[must_use] pub struct Backtrace { inner: Inner, @@ -117,17 +112,21 @@ pub struct Backtrace { /// The current status of a backtrace, indicating whether it was captured or /// whether it is empty for some other reason. +#[stable(feature = "backtrace", since = "1.65.0")] #[non_exhaustive] #[derive(Debug, PartialEq, Eq)] pub enum BacktraceStatus { /// Capturing a backtrace is not supported, likely because it's not /// implemented for the current platform. + #[stable(feature = "backtrace", since = "1.65.0")] Unsupported, /// Capturing a backtrace has been disabled through either the /// `RUST_LIB_BACKTRACE` or `RUST_BACKTRACE` environment variables. + #[stable(feature = "backtrace", since = "1.65.0")] Disabled, /// A backtrace has been captured and the `Backtrace` should print /// reasonable information when rendered. + #[stable(feature = "backtrace", since = "1.65.0")] Captured, } @@ -174,6 +173,7 @@ enum BytesOrWide { Wide(Vec<u16>), } +#[stable(feature = "backtrace", since = "1.65.0")] impl fmt::Debug for Backtrace { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let capture = match &self.inner { @@ -200,6 +200,7 @@ impl fmt::Debug for Backtrace { } } +#[unstable(feature = "backtrace_frames", issue = "79676")] impl fmt::Debug for BacktraceFrame { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let mut dbg = fmt.debug_list(); @@ -288,6 +289,7 @@ impl Backtrace { /// /// To forcibly capture a backtrace regardless of environment variables, use /// the `Backtrace::force_capture` function. + #[stable(feature = "backtrace", since = "1.65.0")] #[inline(never)] // want to make sure there's a frame here to remove pub fn capture() -> Backtrace { if !Backtrace::enabled() { @@ -306,6 +308,7 @@ impl Backtrace { /// Note that capturing a backtrace can be an expensive operation on some /// platforms, so this should be used with caution in performance-sensitive /// parts of code. + #[stable(feature = "backtrace", since = "1.65.0")] #[inline(never)] // want to make sure there's a frame here to remove pub fn force_capture() -> Backtrace { Backtrace::create(Backtrace::force_capture as usize) @@ -313,6 +316,8 @@ impl Backtrace { /// Forcibly captures a disabled backtrace, regardless of environment /// variable configuration. + #[stable(feature = "backtrace", since = "1.65.0")] + #[rustc_const_stable(feature = "backtrace", since = "1.65.0")] pub const fn disabled() -> Backtrace { Backtrace { inner: Inner::Disabled } } @@ -356,6 +361,7 @@ impl Backtrace { /// Returns the status of this backtrace, indicating whether this backtrace /// request was unsupported, disabled, or a stack trace was actually /// captured. + #[stable(feature = "backtrace", since = "1.65.0")] #[must_use] pub fn status(&self) -> BacktraceStatus { match self.inner { @@ -375,6 +381,7 @@ impl<'a> Backtrace { } } +#[stable(feature = "backtrace", since = "1.65.0")] impl fmt::Display for Backtrace { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { let capture = match &self.inner { diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 722df119d22..df7a49d2582 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -1454,7 +1454,6 @@ impl<E> Report<E> { /// /// ```rust /// #![feature(error_reporter)] - /// #![feature(backtrace)] /// #![feature(provide_any)] /// #![feature(error_generic_member_access)] /// # use std::error::Error; diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 6b0c0ad7c21..ebe0ccbdc0b 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -246,6 +246,7 @@ #![cfg_attr(bootstrap, feature(let_chains))] #![feature(let_else)] #![feature(linkage)] +#![feature(link_cfg)] #![feature(min_specialization)] #![feature(must_not_suspend)] #![feature(needs_panic_runtime)] diff --git a/library/std/src/sys/sgx/abi/usercalls/alloc.rs b/library/std/src/sys/sgx/abi/usercalls/alloc.rs index ea24fedd0eb..66fa1efbf10 100644 --- a/library/std/src/sys/sgx/abi/usercalls/alloc.rs +++ b/library/std/src/sys/sgx/abi/usercalls/alloc.rs @@ -115,7 +115,7 @@ pub unsafe trait UserSafe { /// * the pointer is null. /// * the pointed-to range is not in user memory. unsafe fn check_ptr(ptr: *const Self) { - let is_aligned = |p| -> bool { 0 == (p as usize) & (Self::align_of() - 1) }; + let is_aligned = |p: *const u8| -> bool { 0 == p.addr() & (Self::align_of() - 1) }; assert!(is_aligned(ptr as *const u8)); assert!(is_user_range(ptr as _, mem::size_of_val(unsafe { &*ptr }))); diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index b5cc8038ca4..1f2f9d97bdd 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -687,7 +687,11 @@ impl Iterator for ReadDir { impl Drop for Dir { fn drop(&mut self) { let r = unsafe { libc::closedir(self.0) }; - debug_assert_eq!(r, 0); + assert!( + r == 0 || crate::io::Error::last_os_error().kind() == crate::io::ErrorKind::Interrupted, + "unexpected error during closedir: {:?}", + crate::io::Error::last_os_error() + ); } } diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs index abf27e7db78..4741c0c6736 100644 --- a/library/std/src/sys/unix/locks/pthread_condvar.rs +++ b/library/std/src/sys/unix/locks/pthread_condvar.rs @@ -172,7 +172,7 @@ impl Condvar { let mut sys_now = libc::timeval { tv_sec: 0, tv_usec: 0 }; let stable_now = Instant::now(); let r = libc::gettimeofday(&mut sys_now, ptr::null_mut()); - debug_assert_eq!(r, 0); + assert_eq!(r, 0, "unexpected error: {:?}", crate::io::Error::last_os_error()); let nsec = dur.subsec_nanos() as libc::c_long + (sys_now.tv_usec * 1000) as libc::c_long; let extra = (nsec / 1_000_000_000) as libc::time_t; diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 3d0d91460f7..3a375093099 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -295,8 +295,10 @@ pub fn abort_internal() -> ! { cfg_if::cfg_if! { if #[cfg(target_os = "android")] { - #[link(name = "dl")] - #[link(name = "log")] + #[link(name = "dl", kind = "static", modifiers = "-bundle", + cfg(target_feature = "crt-static"))] + #[link(name = "dl", cfg(not(target_feature = "crt-static")))] + #[link(name = "log", cfg(not(target_feature = "crt-static")))] extern "C" {} } else if #[cfg(target_os = "freebsd")] { #[link(name = "execinfo")] diff --git a/library/std/src/sys/unix/rand.rs b/library/std/src/sys/unix/rand.rs index bf49204881d..a6fe07873d7 100644 --- a/library/std/src/sys/unix/rand.rs +++ b/library/std/src/sys/unix/rand.rs @@ -1,13 +1,13 @@ -use crate::mem; -use crate::slice; - pub fn hashmap_random_keys() -> (u64, u64) { - let mut v = (0, 0); - unsafe { - let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8, mem::size_of_val(&v)); - imp::fill_bytes(view); - } - v + const KEY_LEN: usize = core::mem::size_of::<u64>(); + + let mut v = [0u8; KEY_LEN * 2]; + imp::fill_bytes(&mut v); + + let key1 = v[0..KEY_LEN].try_into().unwrap(); + let key2 = v[KEY_LEN..].try_into().unwrap(); + + (u64::from_ne_bytes(key1), u64::from_ne_bytes(key2)) } #[cfg(all( diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 36a3fa6023b..7db3065dee0 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -116,11 +116,9 @@ impl Thread { debug_assert_eq!(ret, 0); } - #[cfg(any(target_os = "linux", target_os = "android"))] + #[cfg(target_os = "android")] pub fn set_name(name: &CStr) { const PR_SET_NAME: libc::c_int = 15; - // pthread wrapper only appeared in glibc 2.12, so we use syscall - // directly. unsafe { libc::prctl( PR_SET_NAME, @@ -132,6 +130,14 @@ impl Thread { } } + #[cfg(target_os = "linux")] + pub fn set_name(name: &CStr) { + unsafe { + // Available since glibc 2.12, musl 1.1.16, and uClibc 1.0.20. + libc::pthread_setname_np(libc::pthread_self(), name.as_ptr()); + } + } + #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))] pub fn set_name(name: &CStr) { unsafe { diff --git a/library/std/src/sys/unsupported/alloc.rs b/library/std/src/sys/unsupported/alloc.rs index 8d5d0a2f5cc..d715ae45401 100644 --- a/library/std/src/sys/unsupported/alloc.rs +++ b/library/std/src/sys/unsupported/alloc.rs @@ -1,15 +1,16 @@ use crate::alloc::{GlobalAlloc, Layout, System}; +use crate::ptr::null_mut; #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { #[inline] unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { - 0 as *mut u8 + null_mut() } #[inline] unsafe fn alloc_zeroed(&self, _layout: Layout) -> *mut u8 { - 0 as *mut u8 + null_mut() } #[inline] @@ -17,6 +18,6 @@ unsafe impl GlobalAlloc for System { #[inline] unsafe fn realloc(&self, _ptr: *mut u8, _layout: Layout, _new_size: usize) -> *mut u8 { - 0 as *mut u8 + null_mut() } } diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 42a1ff730e3..633f17c054b 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -200,6 +200,9 @@ impl<'a> Iterator for CommandArgs<'a> { fn next(&mut self) -> Option<&'a OsStr> { None } + fn size_hint(&self) -> (usize, Option<usize>) { + (0, Some(0)) + } } impl<'a> ExactSizeIterator for CommandArgs<'a> {} diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 44c8a50fd86..479669647c1 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -170,7 +170,6 @@ use crate::ptr::addr_of_mut; use crate::str; use crate::sync::Arc; use crate::sys::thread as imp; -use crate::sys_common::mutex; use crate::sys_common::thread; use crate::sys_common::thread_info; use crate::sys_common::thread_parker::Parker; @@ -1033,24 +1032,48 @@ pub struct ThreadId(NonZeroU64); impl ThreadId { // Generate a new unique thread ID. fn new() -> ThreadId { - // It is UB to attempt to acquire this mutex reentrantly! - static GUARD: mutex::StaticMutex = mutex::StaticMutex::new(); - static mut COUNTER: u64 = 1; - - unsafe { - let guard = GUARD.lock(); - - // If we somehow use up all our bits, panic so that we're not - // covering up subtle bugs of IDs being reused. - if COUNTER == u64::MAX { - drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire. - panic!("failed to generate unique thread ID: bitspace exhausted"); - } - - let id = COUNTER; - COUNTER += 1; + #[cold] + fn exhausted() -> ! { + panic!("failed to generate unique thread ID: bitspace exhausted") + } - ThreadId(NonZeroU64::new(id).unwrap()) + cfg_if::cfg_if! { + if #[cfg(target_has_atomic = "64")] { + use crate::sync::atomic::{AtomicU64, Ordering::Relaxed}; + + static COUNTER: AtomicU64 = AtomicU64::new(0); + + let mut last = COUNTER.load(Relaxed); + loop { + let Some(id) = last.checked_add(1) else { + exhausted(); + }; + + match COUNTER.compare_exchange_weak(last, id, Relaxed, Relaxed) { + Ok(_) => return ThreadId(NonZeroU64::new(id).unwrap()), + Err(id) => last = id, + } + } + } else { + use crate::sys_common::mutex::StaticMutex; + + // It is UB to attempt to acquire this mutex reentrantly! + static GUARD: StaticMutex = StaticMutex::new(); + static mut COUNTER: u64 = 0; + + unsafe { + let guard = GUARD.lock(); + + let Some(id) = COUNTER.checked_add(1) else { + drop(guard); // in case the panic handler ends up calling `ThreadId::new()`, avoid reentrant lock acquire. + exhausted(); + }; + + COUNTER = id; + drop(guard); + ThreadId(NonZeroU64::new(id).unwrap()) + } + } } } diff --git a/library/unwind/build.rs b/library/unwind/build.rs index f88e6a924b5..126e41d1e20 100644 --- a/library/unwind/build.rs +++ b/library/unwind/build.rs @@ -13,13 +13,8 @@ fn main() { let has_unwind = build.is_flag_supported("-lunwind").expect("Unable to invoke compiler"); if has_unwind { - println!("cargo:rustc-link-lib=unwind"); - } else { - println!("cargo:rustc-link-lib=gcc"); + println!("cargo:rustc-cfg=feature=\"system-llvm-libunwind\""); } - - // Android's unwinding library depends on dl_iterate_phdr in `libdl`. - println!("cargo:rustc-link-lib=dl"); } else if target.contains("freebsd") { println!("cargo:rustc-link-lib=gcc_s"); } else if target.contains("netbsd") { diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 4a6ba6e10c3..46fe50cb945 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -55,6 +55,26 @@ cfg_if::cfg_if! { } } +#[cfg(target_os = "android")] +cfg_if::cfg_if! { + if #[cfg(feature = "llvm-libunwind")] { + compile_error!("`llvm-libunwind` is not supported for Android targets"); + } else if #[cfg(feature = "system-llvm-libunwind")] { + #[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] + #[link(name = "unwind", cfg(not(target_feature = "crt-static")))] + extern "C" {} + } else { + #[link(name = "gcc", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] + #[link(name = "gcc", cfg(not(target_feature = "crt-static")))] + extern "C" {} + } +} +// Android's unwinding library depends on dl_iterate_phdr in `libdl`. +#[cfg(target_os = "android")] +#[link(name = "dl", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] +#[link(name = "dl", cfg(not(target_feature = "crt-static")))] +extern "C" {} + // When building with crt-static, we get `gcc_eh` from the `libc` crate, since // glibc needs it, and needs it listed later on the linker command line. We // don't want to duplicate it here. diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index f84de73297a..a242243aaaf 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -1631,14 +1631,12 @@ fn chmod(_path: &Path, _perms: u32) {} /// If code is not 0 (successful exit status), exit status is 101 (rust's default error code.) /// If the test is running and code is an error code, it will cause a panic. fn detail_exit(code: i32) -> ! { - // Successful exit - if code == 0 { - std::process::exit(0); - } - if cfg!(test) { + // if in test and code is an error code, panic with staus code provided + if cfg!(test) && code != 0 { panic!("status code: {}", code); } else { - std::panic::resume_unwind(Box::new(code)); + //otherwise,exit with provided status code + std::process::exit(code); } } diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 5a1f2e70413..1e0f7e9acf4 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -66,16 +66,21 @@ TESTS_IN_2 := \ src/test/ui \ src/tools/linkchecker +## MSVC native builders + +# these intentionally don't use `$(BOOTSTRAP)` so we can test the shebang on Windows ci-subset-1: - $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2:%=--exclude %) + $(Q)$(CFG_SRC_DIR)/x.py test --stage 2 $(TESTS_IN_2:%=--exclude %) ci-subset-2: - $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_2) + $(Q)$(CFG_SRC_DIR)/x.ps1 test --stage 2 $(TESTS_IN_2) + +## MingW native builders TESTS_IN_MINGW_2 := \ src/test/ui ci-mingw-subset-1: - $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %) + $(Q)$(CFG_SRC_DIR)/x.sh test --stage 2 $(TESTS_IN_MINGW_2:%=--exclude %) ci-mingw-subset-2: $(Q)$(BOOTSTRAP) test --stage 2 $(TESTS_IN_MINGW_2) diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 4d548dbb638..8b50d5dc52b 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -325,6 +325,9 @@ impl Step for Llvm { cfg.define("LLVM_PROFDATA_FILE", &path); } + // Disable zstd to avoid a dependency on libzstd.so. + cfg.define("LLVM_ENABLE_ZSTD", "OFF"); + if target != "aarch64-apple-darwin" && !target.contains("windows") { cfg.define("LLVM_ENABLE_ZLIB", "ON"); } else { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index ed1d883d0dc..baad0c75295 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -924,6 +924,11 @@ fn compare_browser_ui_test_version(installed_version: &str, src: &Path) { one used in the CI (`{}`)", installed_version, v ); + eprintln!( + "You can install this version using `npm update browser-ui-test` or by using \ + `npm install browser-ui-test@{}`", + v, + ); } } Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e), diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile index 43cdbbe92e3..a2335687ab3 100644 --- a/src/ci/docker/host-x86_64/arm-android/Dockerfile +++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile @@ -29,7 +29,8 @@ ENV PATH=$PATH:/android/sdk/platform-tools ENV TARGETS=arm-linux-androideabi -ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14 +ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14 \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile index 2f0496d7dd4..c98fa496d48 100644 --- a/src/ci/docker/host-x86_64/dist-android/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile @@ -32,7 +32,8 @@ ENV RUST_CONFIGURE_ARGS \ --i686-linux-android-ndk=/android/ndk/x86-14 \ --aarch64-linux-android-ndk=/android/ndk/arm64-21 \ --x86_64-linux-android-ndk=/android/ndk/x86_64-21 \ - --disable-docs + --disable-docs \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS diff --git a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile index c98fc7dcfff..b0d65428ec6 100644 --- a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile @@ -36,7 +36,8 @@ RUN /scripts/cmake.sh ENV RUST_CONFIGURE_ARGS \ --musl-root-i586=/musl-i586 \ --musl-root-i686=/musl-i686 \ - --disable-docs + --disable-docs \ + --set llvm.allow-old-toolchain # Newer binutils broke things on some vms/distros (i.e., linking against # unknown relocs disabled by the following flag), so we need to go out of our diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile index b0f06569a9c..948fa40dd4b 100644 --- a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile @@ -26,5 +26,6 @@ RUN /scripts/cmake.sh ENV HOSTS=mips-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile index 245c28e1fa3..fd15dbd22c6 100644 --- a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile @@ -25,5 +25,6 @@ RUN /scripts/cmake.sh ENV HOSTS=mips64-unknown-linux-gnuabi64 -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile index 03998c8880a..376bdfb4a2f 100644 --- a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile @@ -26,5 +26,6 @@ RUN /scripts/cmake.sh ENV HOSTS=mips64el-unknown-linux-gnuabi64 -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile index 58617270621..70c8b2a96c8 100644 --- a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile @@ -25,5 +25,6 @@ RUN /scripts/cmake.sh ENV HOSTS=mipsel-unknown-linux-gnu -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile index 92bdc9811fd..fed4be4c30a 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-netbsd/Dockerfile @@ -21,5 +21,6 @@ ENV \ ENV HOSTS=x86_64-unknown-netbsd -ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-extended --disable-docs \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile index 0182ebb8b59..1f8d0a64ea4 100644 --- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile @@ -27,6 +27,7 @@ RUN mkdir -p /config RUN echo "[rust]" > /config/nopt-std-config.toml RUN echo "optimize = false" >> /config/nopt-std-config.toml -ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests +ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu --disable-optimize-tests \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py test --stage 0 --config /config/nopt-std-config.toml library/std \ && python3 ../x.py --stage 2 test diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile index feaab819bdd..7bca0398dea 100644 --- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile @@ -23,7 +23,8 @@ RUN sh /scripts/sccache.sh COPY scripts/cmake.sh /scripts/ RUN /scripts/cmake.sh -ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu +ENV RUST_CONFIGURE_ARGS --build=i686-unknown-linux-gnu \ + --set llvm.allow-old-toolchain # Exclude some tests that are unlikely to be platform specific, to speed up # this slow job. ENV SCRIPT python3 ../x.py --stage 2 test \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile index ee3cd092f4c..bfc6975c19d 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile @@ -26,5 +26,6 @@ RUN sh /scripts/sccache.sh COPY scripts/cmake.sh /scripts/ RUN /scripts/cmake.sh -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu \ + --set llvm.allow-old-toolchain ENV RUST_CHECK_TARGET check-aux diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile index 09d9cda02bd..4bb4042cd7e 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile @@ -22,6 +22,7 @@ RUN sh /scripts/sccache.sh COPY scripts/cmake.sh /scripts/ RUN /scripts/cmake.sh -ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false +ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu --set rust.ignore-git=false \ + --set llvm.allow-old-toolchain ENV SCRIPT python3 ../x.py --stage 2 test distcheck ENV DIST_SRC 1 diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile index df1fbc29cf5..8de9045c3ba 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-12/Dockerfile @@ -1,6 +1,8 @@ FROM ubuntu:20.04 ARG DEBIAN_FRONTEND=noninteractive + +# NOTE: intentionally installs both python2 and python3 so we can test support for both. RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ gcc-multilib \ @@ -10,6 +12,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ ca-certificates \ python2.7 \ + python3.9 \ git \ cmake \ sudo \ @@ -23,6 +26,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ xz-utils \ nodejs +# Install powershell so we can test x.ps1 on Linux +RUN apt-get update && \ + apt-get install -y apt-transport-https software-properties-common && \ + curl -s "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" > packages-microsoft-prod.deb && \ + dpkg -i packages-microsoft-prod.deb && \ + apt-get update && \ + apt-get install -y powershell + COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -33,21 +44,22 @@ ENV RUST_CONFIGURE_ARGS \ --enable-llvm-link-shared \ --set rust.thin-lto-import-instr-limit=10 -ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \ +# NOTE: intentionally uses all of `x.py`, `x.sh`, and `x.ps1` to make sure they all work on Linux. +ENV SCRIPT ../x.py --stage 2 test --exclude src/tools/tidy && \ # Run the `mir-opt` tests again but this time for a 32-bit target. # This enforces that tests using `// EMIT_MIR_FOR_EACH_BIT_WIDTH` have # both 32-bit and 64-bit outputs updated by the PR author, before # the PR is approved and tested for merging. # It will also detect tests lacking `// EMIT_MIR_FOR_EACH_BIT_WIDTH`, # despite having different output on 32-bit vs 64-bit targets. - python2.7 ../x.py --stage 2 test src/test/mir-opt \ + ../x.sh --stage 2 test src/test/mir-opt \ --host='' --target=i686-unknown-linux-gnu && \ # Run the UI test suite again, but in `--pass=check` mode # # This is intended to make sure that both `--pass=check` continues to # work. # - python2.7 ../x.py --stage 2 test src/test/ui --pass=check \ + ../x.ps1 --stage 2 test src/test/ui --pass=check \ --host='' --target=i686-unknown-linux-gnu && \ # Run tidy at the very end, after all the other tests. python2.7 ../x.py --stage 2 test src/tools/tidy 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 2358091a6df..f442a477a7b 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 @@ -81,6 +81,7 @@ COPY host-x86_64/x86_64-gnu-tools/browser-ui-test.version /tmp/ RUN npm install -g browser-ui-test@$(head -n 1 /tmp/browser-ui-test.version) --unsafe-perm=true ENV RUST_CONFIGURE_ARGS \ + --set llvm.allow-old-toolchain \ --build=x86_64-unknown-linux-gnu \ --save-toolstates=/tmp/toolstate/toolstates.json diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 3ad4e3f97a3..a21400cc472 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -596,14 +596,18 @@ jobs: - name: i686-mingw-1 env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu + RUST_CONFIGURE_ARGS: >- + --build=i686-pc-windows-gnu + --set llvm.allow-old-toolchain SCRIPT: make ci-mingw-subset-1 CUSTOM_MINGW: 1 <<: *job-windows-xl - name: i686-mingw-2 env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu + RUST_CONFIGURE_ARGS: >- + --build=i686-pc-windows-gnu + --set llvm.allow-old-toolchain SCRIPT: make ci-mingw-subset-2 CUSTOM_MINGW: 1 <<: *job-windows-xl @@ -611,14 +615,20 @@ jobs: - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-subset-1 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-gnu + --enable-profiler + --set llvm.allow-old-toolchain CUSTOM_MINGW: 1 <<: *job-windows-xl - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-subset-2 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-gnu + --enable-profiler + --set llvm.allow-old-toolchain CUSTOM_MINGW: 1 <<: *job-windows-xl @@ -663,7 +673,11 @@ jobs: - name: dist-i686-mingw env: - RUST_CONFIGURE_ARGS: --build=i686-pc-windows-gnu --enable-full-tools --enable-profiler + RUST_CONFIGURE_ARGS: >- + --build=i686-pc-windows-gnu + --enable-full-tools + --enable-profiler + --set llvm.allow-old-toolchain SCRIPT: python x.py dist CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 @@ -672,7 +686,11 @@ jobs: - name: dist-x86_64-mingw env: SCRIPT: python x.py dist - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-full-tools --enable-profiler + RUST_CONFIGURE_ARGS: >- + --build=x86_64-pc-windows-gnu + --enable-full-tools + --enable-profiler + --set llvm.allow-old-toolchain CUSTOM_MINGW: 1 DIST_REQUIRE_ALL_TOOLS: 1 <<: *job-windows-xl diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index 9c644dd404d..b1854b22a7c 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -30,7 +30,7 @@ Using `rustc` directly: # Compile the Rust staticlib rustc --crate-type=staticlib -Clinker-plugin-lto -Copt-level=2 ./lib.rs # Compile the C code with `-flto=thin` -clang -c -O2 -flto=thin -o main.o ./main.c +clang -c -O2 -flto=thin -o cmain.o ./cmain.c # Link everything, making sure that we use an appropriate linker clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o ``` @@ -41,7 +41,7 @@ Using `cargo`: # Compile the Rust staticlib RUSTFLAGS="-Clinker-plugin-lto" cargo build --release # Compile the C code with `-flto=thin` -clang -c -O2 -flto=thin -o main.o ./main.c +clang -c -O2 -flto=thin -o cmain.o ./cmain.c # Link everything, making sure that we use an appropriate linker clang -flto=thin -fuse-ld=lld -L . -l"name-of-your-rust-lib" -o main -O2 ./cmain.o ``` diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 01dd95e6e40..da15c3c2b1f 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -120,7 +120,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { items: cx.tcx .associated_items(impl_def_id) .in_definition_order() - .map(|x| x.clean(cx)) + .map(|x| clean_middle_assoc_item(x, cx)) .collect::<Vec<_>>(), polarity: ty::ImplPolarity::Positive, kind: ImplKind::Blanket(Box::new(clean_middle_ty(trait_ref.0.self_ty(), cx, None))), diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 58d0aedb023..e56a715e857 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -16,9 +16,10 @@ use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Symbol}; use crate::clean::{ - self, clean_fn_decl_from_did_and_sig, clean_middle_field, clean_middle_ty, - clean_trait_ref_with_bindings, clean_ty, clean_ty_generics, clean_variant_def, - clean_visibility, utils, Attributes, AttributesExt, Clean, ImplKind, ItemId, Type, Visibility, + self, clean_fn_decl_from_did_and_sig, clean_generics, clean_impl_item, clean_middle_assoc_item, + clean_middle_field, clean_middle_ty, clean_trait_ref_with_bindings, clean_ty, + clean_ty_generics, clean_variant_def, clean_visibility, utils, Attributes, AttributesExt, + ImplKind, ItemId, Type, Visibility, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -217,7 +218,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean // which causes methods to have a `pub` prefix, which is invalid since items in traits // can not have a visibility prefix. Thus we override the visibility here manually. // See https://github.com/rust-lang/rust/issues/81274 - clean::Item { visibility: Visibility::Inherited, ..item.clean(cx) } + clean::Item { visibility: Visibility::Inherited, ..clean_middle_assoc_item(item, cx) } }) .collect(); @@ -426,9 +427,9 @@ pub(crate) fn build_impl( true } }) - .map(|item| item.clean(cx)) + .map(|item| clean_impl_item(item, cx)) .collect::<Vec<_>>(), - impl_.generics.clean(cx), + clean_generics(impl_.generics, cx), ), None => ( tcx.associated_items(did) @@ -452,7 +453,7 @@ pub(crate) fn build_impl( item.visibility(tcx).is_public() } }) - .map(|item| item.clean(cx)) + .map(|item| clean_middle_assoc_item(item, cx)) .collect::<Vec<_>>(), clean::enter_impl_trait(cx, |cx| { clean_ty_generics(cx, tcx.generics_of(did), predicates) diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 78b93725537..6e246385489 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -48,75 +48,68 @@ pub(crate) trait Clean<'tcx, T> { fn clean(&self, cx: &mut DocContext<'tcx>) -> T; } -impl<'tcx> Clean<'tcx, Item> for DocModule<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { - let mut items: Vec<Item> = vec![]; - let mut inserted = FxHashSet::default(); - items.extend(self.foreigns.iter().map(|(item, renamed)| { - let item = clean_maybe_renamed_foreign_item(cx, item, *renamed); +pub(crate) fn clean_doc_module<'tcx>(doc: &DocModule<'tcx>, cx: &mut DocContext<'tcx>) -> Item { + let mut items: Vec<Item> = vec![]; + let mut inserted = FxHashSet::default(); + items.extend(doc.foreigns.iter().map(|(item, renamed)| { + let item = clean_maybe_renamed_foreign_item(cx, item, *renamed); + if let Some(name) = item.name { + inserted.insert((item.type_(), name)); + } + item + })); + items.extend(doc.mods.iter().map(|x| { + inserted.insert((ItemType::Module, x.name)); + clean_doc_module(x, cx) + })); + + // Split up imports from all other items. + // + // This covers the case where somebody does an import which should pull in an item, + // but there's already an item with the same namespace and same name. Rust gives + // priority to the not-imported one, so we should, too. + items.extend(doc.items.iter().flat_map(|(item, renamed)| { + // First, lower everything other than imports. + if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { + return Vec::new(); + } + let v = clean_maybe_renamed_item(cx, item, *renamed); + for item in &v { if let Some(name) = item.name { inserted.insert((item.type_(), name)); } - item - })); - items.extend(self.mods.iter().map(|x| { - inserted.insert((ItemType::Module, x.name)); - x.clean(cx) - })); - - // Split up imports from all other items. - // - // This covers the case where somebody does an import which should pull in an item, - // but there's already an item with the same namespace and same name. Rust gives - // priority to the not-imported one, so we should, too. - items.extend(self.items.iter().flat_map(|(item, renamed)| { - // First, lower everything other than imports. - if matches!(item.kind, hir::ItemKind::Use(_, hir::UseKind::Glob)) { - return Vec::new(); - } - let v = clean_maybe_renamed_item(cx, item, *renamed); - for item in &v { - if let Some(name) = item.name { - inserted.insert((item.type_(), name)); - } - } - v - })); - items.extend(self.items.iter().flat_map(|(item, renamed)| { - // Now we actually lower the imports, skipping everything else. - if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind { - let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id())); - clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted) - } else { - // skip everything else - Vec::new() - } - })); - - // determine if we should display the inner contents or - // the outer `mod` item for the source code. - - let span = Span::new({ - let where_outer = self.where_outer(cx.tcx); - let sm = cx.sess().source_map(); - let outer = sm.lookup_char_pos(where_outer.lo()); - let inner = sm.lookup_char_pos(self.where_inner.lo()); - if outer.file.start_pos == inner.file.start_pos { - // mod foo { ... } - where_outer - } else { - // mod foo; (and a separate SourceFile for the contents) - self.where_inner - } - }); + } + v + })); + items.extend(doc.items.iter().flat_map(|(item, renamed)| { + // Now we actually lower the imports, skipping everything else. + if let hir::ItemKind::Use(path, hir::UseKind::Glob) = item.kind { + let name = renamed.unwrap_or_else(|| cx.tcx.hir().name(item.hir_id())); + clean_use_statement(item, name, path, hir::UseKind::Glob, cx, &mut inserted) + } else { + // skip everything else + Vec::new() + } + })); + + // determine if we should display the inner contents or + // the outer `mod` item for the source code. + + let span = Span::new({ + let where_outer = doc.where_outer(cx.tcx); + let sm = cx.sess().source_map(); + let outer = sm.lookup_char_pos(where_outer.lo()); + let inner = sm.lookup_char_pos(doc.where_inner.lo()); + if outer.file.start_pos == inner.file.start_pos { + // mod foo { ... } + where_outer + } else { + // mod foo; (and a separate SourceFile for the contents) + doc.where_inner + } + }); - Item::from_hir_id_and_parts( - self.id, - Some(self.name), - ModuleItem(Module { items, span }), - cx, - ) - } + Item::from_hir_id_and_parts(doc.id, Some(doc.name), ModuleItem(Module { items, span }), cx) } fn clean_generic_bound<'tcx>( @@ -130,7 +123,7 @@ fn clean_generic_bound<'tcx>( let trait_ref = ty::TraitRef::identity(cx.tcx, def_id).skip_binder(); - let generic_args = generic_args.clean(cx); + let generic_args = clean_generic_args(generic_args, cx); let GenericArgs::AngleBracketed { bindings, .. } = generic_args else { bug!("clean: parenthesized `GenericBound::LangItemTrait`"); @@ -568,69 +561,68 @@ fn is_elided_lifetime(param: &hir::GenericParam<'_>) -> bool { matches!(param.kind, hir::GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Elided }) } -impl<'tcx> Clean<'tcx, Generics> for hir::Generics<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Generics { - let impl_trait_params = self - .params - .iter() - .filter(|param| is_impl_trait(param)) - .map(|param| { - let param = clean_generic_param(cx, Some(self), param); - match param.kind { - GenericParamDefKind::Lifetime { .. } => unreachable!(), - GenericParamDefKind::Type { did, ref bounds, .. } => { - cx.impl_trait_bounds.insert(did.into(), bounds.clone()); - } - GenericParamDefKind::Const { .. } => unreachable!(), +pub(crate) fn clean_generics<'tcx>( + gens: &hir::Generics<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Generics { + let impl_trait_params = gens + .params + .iter() + .filter(|param| is_impl_trait(param)) + .map(|param| { + let param = clean_generic_param(cx, Some(gens), param); + match param.kind { + GenericParamDefKind::Lifetime { .. } => unreachable!(), + GenericParamDefKind::Type { did, ref bounds, .. } => { + cx.impl_trait_bounds.insert(did.into(), bounds.clone()); } - param - }) - .collect::<Vec<_>>(); + GenericParamDefKind::Const { .. } => unreachable!(), + } + param + }) + .collect::<Vec<_>>(); - let mut params = Vec::with_capacity(self.params.len()); - for p in self.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { - let p = clean_generic_param(cx, Some(self), p); - params.push(p); - } - params.extend(impl_trait_params); + let mut params = Vec::with_capacity(gens.params.len()); + for p in gens.params.iter().filter(|p| !is_impl_trait(p) && !is_elided_lifetime(p)) { + let p = clean_generic_param(cx, Some(gens), p); + params.push(p); + } + params.extend(impl_trait_params); - let mut generics = Generics { - params, - where_predicates: self - .predicates - .iter() - .filter_map(|x| clean_where_predicate(x, cx)) - .collect(), - }; + let mut generics = Generics { + params, + where_predicates: gens + .predicates + .iter() + .filter_map(|x| clean_where_predicate(x, cx)) + .collect(), + }; - // Some duplicates are generated for ?Sized bounds between type params and where - // predicates. The point in here is to move the bounds definitions from type params - // to where predicates when such cases occur. - for where_pred in &mut generics.where_predicates { - match *where_pred { - WherePredicate::BoundPredicate { - ty: Generic(ref name), ref mut bounds, .. - } => { - if bounds.is_empty() { - for param in &mut generics.params { - match param.kind { - GenericParamDefKind::Lifetime { .. } => {} - GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => { - if ¶m.name == name { - mem::swap(bounds, ty_bounds); - break; - } + // Some duplicates are generated for ?Sized bounds between type params and where + // predicates. The point in here is to move the bounds definitions from type params + // to where predicates when such cases occur. + for where_pred in &mut generics.where_predicates { + match *where_pred { + WherePredicate::BoundPredicate { ty: Generic(ref name), ref mut bounds, .. } => { + if bounds.is_empty() { + for param in &mut generics.params { + match param.kind { + GenericParamDefKind::Lifetime { .. } => {} + GenericParamDefKind::Type { bounds: ref mut ty_bounds, .. } => { + if ¶m.name == name { + mem::swap(bounds, ty_bounds); + break; } - GenericParamDefKind::Const { .. } => {} } + GenericParamDefKind::Const { .. } => {} } } } - _ => continue, } + _ => continue, } - generics } + generics } fn clean_ty_generics<'tcx>( @@ -896,7 +888,7 @@ fn clean_function<'tcx>( ) -> Box<Function> { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args - let generics = generics.clean(cx); + let generics = clean_generics(generics, cx); let args = clean_args_from_types_and_body_id(cx, sig.decl.inputs, body_id); let decl = clean_fn_decl_with_args(cx, sig.decl, args); (generics, decl) @@ -1025,7 +1017,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Required(names)) => { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args - let generics = trait_item.generics.clean(cx); + let generics = clean_generics(trait_item.generics, cx); let args = clean_args_from_types_and_names(cx, sig.decl.inputs, names); let decl = clean_fn_decl_with_args(cx, sig.decl, args); (generics, decl) @@ -1033,7 +1025,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext TyMethodItem(Box::new(Function { decl, generics })) } hir::TraitItemKind::Type(bounds, Some(default)) => { - let generics = enter_impl_trait(cx, |cx| trait_item.generics.clean(cx)); + let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(); let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, default), cx, None); AssocTypeItem( @@ -1046,7 +1038,7 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext ) } hir::TraitItemKind::Type(bounds, None) => { - let generics = enter_impl_trait(cx, |cx| trait_item.generics.clean(cx)); + let generics = enter_impl_trait(cx, |cx| clean_generics(trait_item.generics, cx)); let bounds = bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(); TyAssocTypeItem(Box::new(generics), bounds) } @@ -1058,240 +1050,243 @@ fn clean_trait_item<'tcx>(trait_item: &hir::TraitItem<'tcx>, cx: &mut DocContext }) } -impl<'tcx> Clean<'tcx, Item> for hir::ImplItem<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { - let local_did = self.def_id.to_def_id(); - cx.with_param_env(local_did, |cx| { - let inner = match self.kind { - hir::ImplItemKind::Const(ty, expr) => { - let default = ConstantKind::Local { def_id: local_did, body: expr }; - AssocConstItem(clean_ty(ty, cx), default) - } - hir::ImplItemKind::Fn(ref sig, body) => { - let m = clean_function(cx, sig, self.generics, body); - let defaultness = cx.tcx.impl_defaultness(self.def_id); - MethodItem(m, Some(defaultness)) - } - hir::ImplItemKind::TyAlias(hir_ty) => { - let type_ = clean_ty(hir_ty, cx); - let generics = self.generics.clean(cx); - let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None); - AssocTypeItem( - Box::new(Typedef { type_, generics, item_type: Some(item_type) }), - Vec::new(), - ) - } - }; +pub(crate) fn clean_impl_item<'tcx>( + impl_: &hir::ImplItem<'tcx>, + cx: &mut DocContext<'tcx>, +) -> Item { + let local_did = impl_.def_id.to_def_id(); + cx.with_param_env(local_did, |cx| { + let inner = match impl_.kind { + hir::ImplItemKind::Const(ty, expr) => { + let default = ConstantKind::Local { def_id: local_did, body: expr }; + AssocConstItem(clean_ty(ty, cx), default) + } + hir::ImplItemKind::Fn(ref sig, body) => { + let m = clean_function(cx, sig, impl_.generics, body); + let defaultness = cx.tcx.impl_defaultness(impl_.def_id); + MethodItem(m, Some(defaultness)) + } + hir::ImplItemKind::TyAlias(hir_ty) => { + let type_ = clean_ty(hir_ty, cx); + let generics = clean_generics(impl_.generics, cx); + let item_type = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None); + AssocTypeItem( + Box::new(Typedef { type_, generics, item_type: Some(item_type) }), + Vec::new(), + ) + } + }; - let mut what_rustc_thinks = - Item::from_def_id_and_parts(local_did, Some(self.ident.name), inner, cx); + let mut what_rustc_thinks = + Item::from_def_id_and_parts(local_did, Some(impl_.ident.name), inner, cx); - let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(self.def_id)); + let impl_ref = cx.tcx.impl_trait_ref(cx.tcx.local_parent(impl_.def_id)); - // Trait impl items always inherit the impl's visibility -- - // we don't want to show `pub`. - if impl_ref.is_some() { - what_rustc_thinks.visibility = Inherited; - } + // Trait impl items always inherit the impl's visibility -- + // we don't want to show `pub`. + if impl_ref.is_some() { + what_rustc_thinks.visibility = Inherited; + } - what_rustc_thinks - }) - } + what_rustc_thinks + }) } -impl<'tcx> Clean<'tcx, Item> for ty::AssocItem { - fn clean(&self, cx: &mut DocContext<'tcx>) -> Item { - let tcx = cx.tcx; - let kind = match self.kind { - ty::AssocKind::Const => { - let ty = clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)); - - let provided = match self.container { - ty::ImplContainer => true, - ty::TraitContainer => tcx.impl_defaultness(self.def_id).has_value(), - }; - if provided { - AssocConstItem(ty, ConstantKind::Extern { def_id: self.def_id }) - } else { - TyAssocConstItem(ty) - } +pub(crate) fn clean_middle_assoc_item<'tcx>( + assoc_item: &ty::AssocItem, + cx: &mut DocContext<'tcx>, +) -> Item { + let tcx = cx.tcx; + let kind = match assoc_item.kind { + ty::AssocKind::Const => { + let ty = clean_middle_ty(tcx.type_of(assoc_item.def_id), cx, Some(assoc_item.def_id)); + + let provided = match assoc_item.container { + ty::ImplContainer => true, + ty::TraitContainer => tcx.impl_defaultness(assoc_item.def_id).has_value(), + }; + if provided { + AssocConstItem(ty, ConstantKind::Extern { def_id: assoc_item.def_id }) + } else { + TyAssocConstItem(ty) } - ty::AssocKind::Fn => { - let generics = clean_ty_generics( - cx, - tcx.generics_of(self.def_id), - tcx.explicit_predicates_of(self.def_id), - ); - let sig = tcx.fn_sig(self.def_id); - let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(self.def_id), sig); - - if self.fn_has_self_parameter { - let self_ty = match self.container { - ty::ImplContainer => tcx.type_of(self.container_id(tcx)), - ty::TraitContainer => tcx.types.self_param, - }; - let self_arg_ty = sig.input(0).skip_binder(); - if self_arg_ty == self_ty { - decl.inputs.values[0].type_ = Generic(kw::SelfUpper); - } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() { - if ty == self_ty { - match decl.inputs.values[0].type_ { - BorrowedRef { ref mut type_, .. } => { - **type_ = Generic(kw::SelfUpper) - } - _ => unreachable!(), - } + } + ty::AssocKind::Fn => { + let generics = clean_ty_generics( + cx, + tcx.generics_of(assoc_item.def_id), + tcx.explicit_predicates_of(assoc_item.def_id), + ); + let sig = tcx.fn_sig(assoc_item.def_id); + let mut decl = clean_fn_decl_from_did_and_sig(cx, Some(assoc_item.def_id), sig); + + if assoc_item.fn_has_self_parameter { + let self_ty = match assoc_item.container { + ty::ImplContainer => tcx.type_of(assoc_item.container_id(tcx)), + ty::TraitContainer => tcx.types.self_param, + }; + let self_arg_ty = sig.input(0).skip_binder(); + if self_arg_ty == self_ty { + decl.inputs.values[0].type_ = Generic(kw::SelfUpper); + } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() { + if ty == self_ty { + match decl.inputs.values[0].type_ { + BorrowedRef { ref mut type_, .. } => **type_ = Generic(kw::SelfUpper), + _ => unreachable!(), } } } + } - let provided = match self.container { - ty::ImplContainer => true, - ty::TraitContainer => self.defaultness(tcx).has_value(), + let provided = match assoc_item.container { + ty::ImplContainer => true, + ty::TraitContainer => assoc_item.defaultness(tcx).has_value(), + }; + if provided { + let defaultness = match assoc_item.container { + ty::ImplContainer => Some(assoc_item.defaultness(tcx)), + ty::TraitContainer => None, }; - if provided { - let defaultness = match self.container { - ty::ImplContainer => Some(self.defaultness(tcx)), - ty::TraitContainer => None, - }; - MethodItem(Box::new(Function { generics, decl }), defaultness) - } else { - TyMethodItem(Box::new(Function { generics, decl })) - } + MethodItem(Box::new(Function { generics, decl }), defaultness) + } else { + TyMethodItem(Box::new(Function { generics, decl })) } - ty::AssocKind::Type => { - let my_name = self.name; - - fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool { - match (¶m.kind, arg) { - (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty))) - if *ty == param.name => - { - true - } - ( - GenericParamDefKind::Lifetime { .. }, - GenericArg::Lifetime(Lifetime(lt)), - ) if *lt == param.name => true, - (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => { - match &c.kind { - ConstantKind::TyConst { expr } => expr == param.name.as_str(), - _ => false, - } - } - _ => false, + } + ty::AssocKind::Type => { + let my_name = assoc_item.name; + + fn param_eq_arg(param: &GenericParamDef, arg: &GenericArg) -> bool { + match (¶m.kind, arg) { + (GenericParamDefKind::Type { .. }, GenericArg::Type(Type::Generic(ty))) + if *ty == param.name => + { + true + } + (GenericParamDefKind::Lifetime { .. }, GenericArg::Lifetime(Lifetime(lt))) + if *lt == param.name => + { + true } + (GenericParamDefKind::Const { .. }, GenericArg::Const(c)) => match &c.kind { + ConstantKind::TyConst { expr } => expr == param.name.as_str(), + _ => false, + }, + _ => false, } + } - if let ty::TraitContainer = self.container { - let bounds = tcx.explicit_item_bounds(self.def_id); - let predicates = ty::GenericPredicates { parent: None, predicates: bounds }; - let mut generics = - clean_ty_generics(cx, tcx.generics_of(self.def_id), predicates); - // Filter out the bounds that are (likely?) directly attached to the associated type, - // as opposed to being located in the where clause. - let mut bounds = generics - .where_predicates - .drain_filter(|pred| match *pred { - WherePredicate::BoundPredicate { - ty: QPath { ref assoc, ref self_type, ref trait_, .. }, - .. - } => { - if assoc.name != my_name { - return false; - } - if trait_.def_id() != self.container_id(tcx) { - return false; - } - match **self_type { - Generic(ref s) if *s == kw::SelfUpper => {} - _ => return false, - } - match &assoc.args { - GenericArgs::AngleBracketed { args, bindings } => { - if !bindings.is_empty() - || generics - .params - .iter() - .zip(args.iter()) - .any(|(param, arg)| !param_eq_arg(param, arg)) - { - return false; - } - } - GenericArgs::Parenthesized { .. } => { - // The only time this happens is if we're inside the rustdoc for Fn(), - // which only has one associated type, which is not a GAT, so whatever. + if let ty::TraitContainer = assoc_item.container { + let bounds = tcx.explicit_item_bounds(assoc_item.def_id); + let predicates = ty::GenericPredicates { parent: None, predicates: bounds }; + let mut generics = + clean_ty_generics(cx, tcx.generics_of(assoc_item.def_id), predicates); + // Filter out the bounds that are (likely?) directly attached to the associated type, + // as opposed to being located in the where clause. + let mut bounds = generics + .where_predicates + .drain_filter(|pred| match *pred { + WherePredicate::BoundPredicate { + ty: QPath { ref assoc, ref self_type, ref trait_, .. }, + .. + } => { + if assoc.name != my_name { + return false; + } + if trait_.def_id() != assoc_item.container_id(tcx) { + return false; + } + match **self_type { + Generic(ref s) if *s == kw::SelfUpper => {} + _ => return false, + } + match &assoc.args { + GenericArgs::AngleBracketed { args, bindings } => { + if !bindings.is_empty() + || generics + .params + .iter() + .zip(args.iter()) + .any(|(param, arg)| !param_eq_arg(param, arg)) + { + return false; } } - true - } - _ => false, - }) - .flat_map(|pred| { - if let WherePredicate::BoundPredicate { bounds, .. } = pred { - bounds - } else { - unreachable!() + GenericArgs::Parenthesized { .. } => { + // The only time this happens is if we're inside the rustdoc for Fn(), + // which only has one associated type, which is not a GAT, so whatever. + } } - }) - .collect::<Vec<_>>(); - // Our Sized/?Sized bound didn't get handled when creating the generics - // because we didn't actually get our whole set of bounds until just now - // (some of them may have come from the trait). If we do have a sized - // bound, we remove it, and if we don't then we add the `?Sized` bound - // at the end. - match bounds.iter().position(|b| b.is_sized_bound(cx)) { - Some(i) => { - bounds.remove(i); + true + } + _ => false, + }) + .flat_map(|pred| { + if let WherePredicate::BoundPredicate { bounds, .. } = pred { + bounds + } else { + unreachable!() } - None => bounds.push(GenericBound::maybe_sized(cx)), + }) + .collect::<Vec<_>>(); + // Our Sized/?Sized bound didn't get handled when creating the generics + // because we didn't actually get our whole set of bounds until just now + // (some of them may have come from the trait). If we do have a sized + // bound, we remove it, and if we don't then we add the `?Sized` bound + // at the end. + match bounds.iter().position(|b| b.is_sized_bound(cx)) { + Some(i) => { + bounds.remove(i); } + None => bounds.push(GenericBound::maybe_sized(cx)), + } - if tcx.impl_defaultness(self.def_id).has_value() { - AssocTypeItem( - Box::new(Typedef { - type_: clean_middle_ty( - tcx.type_of(self.def_id), - cx, - Some(self.def_id), - ), - generics, - // FIXME: should we obtain the Type from HIR and pass it on here? - item_type: None, - }), - bounds, - ) - } else { - TyAssocTypeItem(Box::new(generics), bounds) - } - } else { - // FIXME: when could this happen? Associated items in inherent impls? + if tcx.impl_defaultness(assoc_item.def_id).has_value() { AssocTypeItem( Box::new(Typedef { - type_: clean_middle_ty(tcx.type_of(self.def_id), cx, Some(self.def_id)), - generics: Generics { params: Vec::new(), where_predicates: Vec::new() }, + type_: clean_middle_ty( + tcx.type_of(assoc_item.def_id), + cx, + Some(assoc_item.def_id), + ), + generics, + // FIXME: should we obtain the Type from HIR and pass it on here? item_type: None, }), - Vec::new(), + bounds, ) + } else { + TyAssocTypeItem(Box::new(generics), bounds) } + } else { + // FIXME: when could this happen? Associated items in inherent impls? + AssocTypeItem( + Box::new(Typedef { + type_: clean_middle_ty( + tcx.type_of(assoc_item.def_id), + cx, + Some(assoc_item.def_id), + ), + generics: Generics { params: Vec::new(), where_predicates: Vec::new() }, + item_type: None, + }), + Vec::new(), + ) } - }; + } + }; - let mut what_rustc_thinks = - Item::from_def_id_and_parts(self.def_id, Some(self.name), kind, cx); + let mut what_rustc_thinks = + Item::from_def_id_and_parts(assoc_item.def_id, Some(assoc_item.name), kind, cx); - let impl_ref = tcx.impl_trait_ref(tcx.parent(self.def_id)); + let impl_ref = tcx.impl_trait_ref(tcx.parent(assoc_item.def_id)); - // Trait impl items always inherit the impl's visibility -- - // we don't want to show `pub`. - if impl_ref.is_some() { - what_rustc_thinks.visibility = Visibility::Inherited; - } - - what_rustc_thinks + // Trait impl items always inherit the impl's visibility -- + // we don't want to show `pub`. + if impl_ref.is_some() { + what_rustc_thinks.visibility = Visibility::Inherited; } + + what_rustc_thinks } fn clean_qpath<'tcx>(hir_ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type { @@ -1831,39 +1826,44 @@ fn clean_path<'tcx>(path: &hir::Path<'tcx>, cx: &mut DocContext<'tcx>) -> Path { Path { res: path.res, segments: path.segments.iter().map(|x| x.clean(cx)).collect() } } -impl<'tcx> Clean<'tcx, GenericArgs> for hir::GenericArgs<'tcx> { - fn clean(&self, cx: &mut DocContext<'tcx>) -> GenericArgs { - if self.parenthesized { - let output = clean_ty(self.bindings[0].ty(), cx); - let output = - if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None }; - let inputs = self.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into(); - GenericArgs::Parenthesized { inputs, output } - } else { - let args = self - .args - .iter() - .map(|arg| match arg { - hir::GenericArg::Lifetime(lt) if !lt.is_elided() => { - GenericArg::Lifetime(clean_lifetime(*lt, cx)) - } - hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), - hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)), - hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))), - hir::GenericArg::Infer(_inf) => GenericArg::Infer, - }) - .collect::<Vec<_>>() - .into(); - let bindings = - self.bindings.iter().map(|x| clean_type_binding(x, cx)).collect::<Vec<_>>().into(); - GenericArgs::AngleBracketed { args, bindings } - } +fn clean_generic_args<'tcx>( + generic_args: &hir::GenericArgs<'tcx>, + cx: &mut DocContext<'tcx>, +) -> GenericArgs { + if generic_args.parenthesized { + let output = clean_ty(generic_args.bindings[0].ty(), cx); + let output = if output != Type::Tuple(Vec::new()) { Some(Box::new(output)) } else { None }; + let inputs = + generic_args.inputs().iter().map(|x| clean_ty(x, cx)).collect::<Vec<_>>().into(); + GenericArgs::Parenthesized { inputs, output } + } else { + let args = generic_args + .args + .iter() + .map(|arg| match arg { + hir::GenericArg::Lifetime(lt) if !lt.is_elided() => { + GenericArg::Lifetime(clean_lifetime(*lt, cx)) + } + hir::GenericArg::Lifetime(_) => GenericArg::Lifetime(Lifetime::elided()), + hir::GenericArg::Type(ty) => GenericArg::Type(clean_ty(ty, cx)), + hir::GenericArg::Const(ct) => GenericArg::Const(Box::new(clean_const(ct, cx))), + hir::GenericArg::Infer(_inf) => GenericArg::Infer, + }) + .collect::<Vec<_>>() + .into(); + let bindings = generic_args + .bindings + .iter() + .map(|x| clean_type_binding(x, cx)) + .collect::<Vec<_>>() + .into(); + GenericArgs::AngleBracketed { args, bindings } } } impl<'tcx> Clean<'tcx, PathSegment> for hir::PathSegment<'tcx> { fn clean(&self, cx: &mut DocContext<'tcx>) -> PathSegment { - PathSegment { name: self.ident.name, args: self.args().clean(cx) } + PathSegment { name: self.ident.name, args: clean_generic_args(self.args(), cx) } } } @@ -1905,32 +1905,32 @@ fn clean_maybe_renamed_item<'tcx>( }), ItemKind::OpaqueTy(ref ty) => OpaqueTyItem(OpaqueTy { bounds: ty.bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), - generics: ty.generics.clean(cx), + generics: clean_generics(ty.generics, cx), }), ItemKind::TyAlias(hir_ty, generics) => { let rustdoc_ty = clean_ty(hir_ty, cx); let ty = clean_middle_ty(hir_ty_to_ty(cx.tcx, hir_ty), cx, None); TypedefItem(Box::new(Typedef { type_: rustdoc_ty, - generics: generics.clean(cx), + generics: clean_generics(generics, cx), item_type: Some(ty), })) } ItemKind::Enum(ref def, generics) => EnumItem(Enum { variants: def.variants.iter().map(|v| v.clean(cx)).collect(), - generics: generics.clean(cx), + generics: clean_generics(generics, cx), }), ItemKind::TraitAlias(generics, bounds) => TraitAliasItem(TraitAlias { - generics: generics.clean(cx), + generics: clean_generics(generics, cx), bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }), ItemKind::Union(ref variant_data, generics) => UnionItem(Union { - generics: generics.clean(cx), + generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), ItemKind::Struct(ref variant_data, generics) => StructItem(Struct { struct_type: CtorKind::from_hir(variant_data), - generics: generics.clean(cx), + generics: clean_generics(generics, cx), fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(), }), ItemKind::Impl(impl_) => return clean_impl(impl_, item.hir_id(), cx), @@ -1953,7 +1953,7 @@ fn clean_maybe_renamed_item<'tcx>( TraitItem(Trait { def_id, items, - generics: generics.clean(cx), + generics: clean_generics(generics, cx), bounds: bounds.iter().filter_map(|x| clean_generic_bound(x, cx)).collect(), }) } @@ -1988,8 +1988,11 @@ fn clean_impl<'tcx>( let tcx = cx.tcx; let mut ret = Vec::new(); let trait_ = impl_.of_trait.as_ref().map(|t| clean_trait_ref(t, cx)); - let items = - impl_.items.iter().map(|ii| tcx.hir().impl_item(ii.id).clean(cx)).collect::<Vec<_>>(); + let items = impl_ + .items + .iter() + .map(|ii| clean_impl_item(tcx.hir().impl_item(ii.id), cx)) + .collect::<Vec<_>>(); let def_id = tcx.hir().local_def_id(hir_id); // If this impl block is an implementation of the Deref trait, then we @@ -2006,7 +2009,7 @@ fn clean_impl<'tcx>( let mut make_item = |trait_: Option<Path>, for_: Type, items: Vec<Item>| { let kind = ImplItem(Box::new(Impl { unsafety: impl_.unsafety, - generics: impl_.generics.clean(cx), + generics: clean_generics(impl_.generics, cx), trait_, for_, items, @@ -2203,7 +2206,7 @@ fn clean_maybe_renamed_foreign_item<'tcx>( hir::ForeignItemKind::Fn(decl, names, generics) => { let (generics, decl) = enter_impl_trait(cx, |cx| { // NOTE: generics must be cleaned before args - let generics = generics.clean(cx); + let generics = clean_generics(generics, cx); let args = clean_args_from_types_and_names(cx, decl.inputs, names); let decl = clean_fn_decl_with_args(cx, decl, args); (generics, decl) @@ -2230,7 +2233,10 @@ fn clean_type_binding<'tcx>( cx: &mut DocContext<'tcx>, ) -> TypeBinding { TypeBinding { - assoc: PathSegment { name: type_binding.ident.name, args: type_binding.gen_args.clean(cx) }, + assoc: PathSegment { + name: type_binding.ident.name, + args: clean_generic_args(type_binding.gen_args, cx), + }, kind: match type_binding.kind { hir::TypeBindingKind::Equality { ref term } => { TypeBindingKind::Equality { term: clean_hir_term(term, cx) } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 0e6de842cc2..91d5758077c 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -2495,14 +2495,15 @@ impl SubstParam { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] mod size_asserts { use super::*; + use rustc_data_structures::static_assert_size; // These are in alphabetical order, which is easy to maintain. - rustc_data_structures::static_assert_size!(Crate, 72); // frequently moved by-value - rustc_data_structures::static_assert_size!(DocFragment, 32); - rustc_data_structures::static_assert_size!(GenericArg, 80); - rustc_data_structures::static_assert_size!(GenericArgs, 32); - rustc_data_structures::static_assert_size!(GenericParamDef, 56); - rustc_data_structures::static_assert_size!(Item, 56); - rustc_data_structures::static_assert_size!(ItemKind, 112); - rustc_data_structures::static_assert_size!(PathSegment, 40); - rustc_data_structures::static_assert_size!(Type, 72); + static_assert_size!(Crate, 72); // frequently moved by-value + static_assert_size!(DocFragment, 32); + static_assert_size!(GenericArg, 80); + static_assert_size!(GenericArgs, 32); + static_assert_size!(GenericParamDef, 56); + static_assert_size!(Item, 56); + static_assert_size!(ItemKind, 112); + static_assert_size!(PathSegment, 40); + static_assert_size!(Type, 72); } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 43e71e90a6f..718cbbd2b83 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -2,9 +2,9 @@ use crate::clean::auto_trait::AutoTraitFinder; use crate::clean::blanket_impl::BlanketImplFinder; use crate::clean::render_macro_matchers::render_macro_matcher; use crate::clean::{ - clean_middle_const, clean_middle_region, clean_middle_ty, inline, Clean, Crate, ExternalCrate, - Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path, PathSegment, - Primitive, PrimitiveType, Type, TypeBinding, Visibility, + clean_doc_module, clean_middle_const, clean_middle_region, clean_middle_ty, inline, Crate, + ExternalCrate, Generic, GenericArg, GenericArgs, ImportSource, Item, ItemKind, Lifetime, Path, + PathSegment, Primitive, PrimitiveType, Type, TypeBinding, Visibility, }; use crate::core::DocContext; use crate::formats::item_type::ItemType; @@ -37,7 +37,7 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate { // Clean the crate, translating the entire librustc_ast AST to one that is // understood by rustdoc. - let mut module = module.clean(cx); + let mut module = clean_doc_module(&module, cx); match *module.kind { ItemKind::ModuleItem(ref module) => { diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 35964e3ba38..20ae102bc27 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1289,14 +1289,9 @@ impl<'a, 'hir, 'tcx> intravisit::Visitor<'hir> for HirCollector<'a, 'hir, 'tcx> }); } - fn visit_variant( - &mut self, - v: &'hir hir::Variant<'_>, - g: &'hir hir::Generics<'_>, - item_id: hir::HirId, - ) { + fn visit_variant(&mut self, v: &'hir hir::Variant<'_>) { self.visit_testable(v.ident.to_string(), v.id, v.span, |this| { - intravisit::walk_variant(this, v, g, item_id); + intravisit::walk_variant(this, v); }); } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 36a47b05cb9..3dee4d1acc8 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -152,7 +152,7 @@ impl Buffer { } } -fn comma_sep<T: fmt::Display>( +pub(crate) fn comma_sep<T: fmt::Display>( items: impl Iterator<Item = T>, space_after_comma: bool, ) -> impl fmt::Display { diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index 05547ea1515..5a6720a8dd9 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -33,27 +33,39 @@ pub(crate) struct HrefContext<'a, 'b, 'c> { /// Decorations are represented as a map from CSS class to vector of character ranges. /// Each range will be wrapped in a span with that class. +#[derive(Default)] pub(crate) struct DecorationInfo(pub(crate) FxHashMap<&'static str, Vec<(u32, u32)>>); -/// Highlights `src`, returning the HTML output. -pub(crate) fn render_with_highlighting( +#[derive(Eq, PartialEq, Clone, Copy)] +pub(crate) enum Tooltip { + Ignore, + CompileFail, + ShouldPanic, + Edition(Edition), + None, +} + +/// Highlights `src` as an inline example, returning the HTML output. +pub(crate) fn render_example_with_highlighting( src: &str, out: &mut Buffer, - class: Option<&str>, + tooltip: Tooltip, playground_button: Option<&str>, - tooltip: Option<(Option<Edition>, &str)>, - edition: Edition, - extra_content: Option<Buffer>, - href_context: Option<HrefContext<'_, '_, '_>>, - decoration_info: Option<DecorationInfo>, ) { - debug!("highlighting: ================\n{}\n==============", src); - if let Some((edition_info, class)) = tooltip { + let class = match tooltip { + Tooltip::Ignore => " ignore", + Tooltip::CompileFail => " compile_fail", + Tooltip::ShouldPanic => " should_panic", + Tooltip::Edition(_) => " edition", + Tooltip::None => "", + }; + + if tooltip != Tooltip::None { write!( out, - "<div class='information'><div class='tooltip {}'{}>ⓘ</div></div>", + "<div class='information'><div class='tooltip{}'{}>ⓘ</div></div>", class, - if let Some(edition_info) = edition_info { + if let Tooltip::Edition(edition_info) = tooltip { format!(" data-edition=\"{}\"", edition_info) } else { String::new() @@ -61,20 +73,40 @@ pub(crate) fn render_with_highlighting( ); } - write_header(out, class, extra_content); - write_code(out, src, edition, href_context, decoration_info); + write_header(out, &format!("rust-example-rendered{}", class), None); + write_code(out, src, None, None); write_footer(out, playground_button); } -fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buffer>) { +/// Highlights `src` as a macro, returning the HTML output. +pub(crate) fn render_macro_with_highlighting(src: &str, out: &mut Buffer) { + write_header(out, "macro", None); + write_code(out, src, None, None); + write_footer(out, None); +} + +/// Highlights `src` as a source code page, returning the HTML output. +pub(crate) fn render_source_with_highlighting( + src: &str, + out: &mut Buffer, + line_numbers: Buffer, + href_context: HrefContext<'_, '_, '_>, + decoration_info: DecorationInfo, +) { + write_header(out, "", Some(line_numbers)); + write_code(out, src, Some(href_context), Some(decoration_info)); + write_footer(out, None); +} + +fn write_header(out: &mut Buffer, class: &str, extra_content: Option<Buffer>) { write!(out, "<div class=\"example-wrap\">"); if let Some(extra) = extra_content { out.push_buffer(extra); } - if let Some(class) = class { - write!(out, "<pre class=\"rust {}\">", class); - } else { + if class.is_empty() { write!(out, "<pre class=\"rust\">"); + } else { + write!(out, "<pre class=\"rust {}\">", class); } write!(out, "<code>"); } @@ -93,7 +125,6 @@ fn write_header(out: &mut Buffer, class: Option<&str>, extra_content: Option<Buf fn write_code( out: &mut Buffer, src: &str, - edition: Edition, href_context: Option<HrefContext<'_, '_, '_>>, decoration_info: Option<DecorationInfo>, ) { @@ -102,7 +133,6 @@ fn write_code( let mut closing_tags: Vec<&'static str> = Vec::new(); Classifier::new( &src, - edition, href_context.as_ref().map(|c| c.file_span).unwrap_or(DUMMY_SP), decoration_info, ) @@ -220,7 +250,7 @@ impl<'a> Iterator for TokenIter<'a> { } /// Classifies into identifier class; returns `None` if this is a non-keyword identifier. -fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) -> Option<Class> { +fn get_real_ident_class(text: &str, allow_path_keywords: bool) -> Option<Class> { let ignore: &[&str] = if allow_path_keywords { &["self", "Self", "super", "crate"] } else { &["self", "Self"] }; if ignore.iter().any(|k| *k == text) { @@ -229,7 +259,7 @@ fn get_real_ident_class(text: &str, edition: Edition, allow_path_keywords: bool) Some(match text { "ref" | "mut" => Class::RefKeyWord, "false" | "true" => Class::Bool, - _ if Symbol::intern(text).is_reserved(|| edition) => Class::KeyWord, + _ if Symbol::intern(text).is_reserved(|| Edition::Edition2021) => Class::KeyWord, _ => return None, }) } @@ -311,7 +341,6 @@ struct Classifier<'a> { in_attribute: bool, in_macro: bool, in_macro_nonterminal: bool, - edition: Edition, byte_pos: u32, file_span: Span, src: &'a str, @@ -321,12 +350,7 @@ struct Classifier<'a> { impl<'a> Classifier<'a> { /// Takes as argument the source code to HTML-ify, the rust edition to use and the source code /// file span which will be used later on by the `span_correspondance_map`. - fn new( - src: &str, - edition: Edition, - file_span: Span, - decoration_info: Option<DecorationInfo>, - ) -> Classifier<'_> { + fn new(src: &str, file_span: Span, decoration_info: Option<DecorationInfo>) -> Classifier<'_> { let tokens = PeekIter::new(TokenIter { src }); let decorations = decoration_info.map(Decorations::new); Classifier { @@ -334,7 +358,6 @@ impl<'a> Classifier<'a> { in_attribute: false, in_macro: false, in_macro_nonterminal: false, - edition, byte_pos: 0, file_span, src, @@ -354,7 +377,6 @@ impl<'a> Classifier<'a> { let start = self.byte_pos as usize; let mut pos = start; let mut has_ident = false; - let edition = self.edition; loop { let mut nb = 0; @@ -376,7 +398,7 @@ impl<'a> Classifier<'a> { if let Some((None, text)) = self.tokens.peek().map(|(token, text)| { if *token == TokenKind::Ident { - let class = get_real_ident_class(text, edition, true); + let class = get_real_ident_class(text, true); (class, text) } else { // Doesn't matter which Class we put in here... @@ -634,7 +656,7 @@ impl<'a> Classifier<'a> { sink(Highlight::Token { text, class: None }); return; } - TokenKind::Ident => match get_real_ident_class(text, self.edition, false) { + TokenKind::Ident => match get_real_ident_class(text, false) { None => match text { "Option" | "Result" => Class::PreludeTy, "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 1fea7e983b4..4861a8ad32d 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -3,7 +3,6 @@ use crate::html::format::Buffer; use expect_test::expect_file; use rustc_data_structures::fx::FxHashMap; use rustc_span::create_default_session_globals_then; -use rustc_span::edition::Edition; const STYLE: &str = r#" <style> @@ -23,7 +22,7 @@ fn test_html_highlighting() { let src = include_str!("fixtures/sample.rs"); let html = { let mut out = Buffer::new(); - write_code(&mut out, src, Edition::Edition2018, None, None); + write_code(&mut out, src, None, None); format!("{}<pre><code>{}</code></pre>\n", STYLE, out.into_inner()) }; expect_file!["fixtures/sample.html"].assert_eq(&html); @@ -37,7 +36,7 @@ fn test_dos_backline() { println!(\"foo\");\r\n\ }\r\n"; let mut html = Buffer::new(); - write_code(&mut html, src, Edition::Edition2018, None, None); + write_code(&mut html, src, None, None); expect_file!["fixtures/dos_line.html"].assert_eq(&html.into_inner()); }); } @@ -51,7 +50,7 @@ let x = super::b::foo; let y = Self::whatever;"; let mut html = Buffer::new(); - write_code(&mut html, src, Edition::Edition2018, None, None); + write_code(&mut html, src, None, None); expect_file!["fixtures/highlight.html"].assert_eq(&html.into_inner()); }); } @@ -61,7 +60,7 @@ fn test_union_highlighting() { create_default_session_globals_then(|| { let src = include_str!("fixtures/union.rs"); let mut html = Buffer::new(); - write_code(&mut html, src, Edition::Edition2018, None, None); + write_code(&mut html, src, None, None); expect_file!["fixtures/union.html"].assert_eq(&html.into_inner()); }); } @@ -75,7 +74,7 @@ let y = 2;"; decorations.insert("example", vec![(0, 10)]); let mut html = Buffer::new(); - write_code(&mut html, src, Edition::Edition2018, None, Some(DecorationInfo(decorations))); + write_code(&mut html, src, None, Some(DecorationInfo(decorations))); expect_file!["fixtures/decorations.html"].assert_eq(&html.into_inner()); }); } diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 52a2effca0f..ec2e129c364 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -330,34 +330,27 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> { }); let tooltip = if ignore != Ignore::None { - Some((None, "ignore")) + highlight::Tooltip::Ignore } else if compile_fail { - Some((None, "compile_fail")) + highlight::Tooltip::CompileFail } else if should_panic { - Some((None, "should_panic")) + highlight::Tooltip::ShouldPanic } else if explicit_edition { - Some((Some(edition), "edition")) + highlight::Tooltip::Edition(edition) } else { - None + highlight::Tooltip::None }; // insert newline to clearly separate it from the // previous block so we can shorten the html output let mut s = Buffer::new(); s.push_str("\n"); - highlight::render_with_highlighting( + + highlight::render_example_with_highlighting( &text, &mut s, - Some(&format!( - "rust-example-rendered{}", - if let Some((_, class)) = tooltip { format!(" {}", class) } else { String::new() } - )), - playground_button.as_deref(), tooltip, - edition, - None, - None, - None, + playground_button.as_deref(), ); Some(Event::Html(s.into_inner().into())) } @@ -1446,6 +1439,8 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> { map.insert("not-displayed".into(), 1); map.insert("alternative-display".into(), 1); map.insert("search".into(), 1); + map.insert("crate-search".into(), 1); + map.insert("crate-search-div".into(), 1); // This is the list of IDs used in HTML generated in Rust (including the ones // used in tera template files). map.insert("mainThemeStyle".into(), 1); @@ -1453,7 +1448,6 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> { map.insert("settings-menu".into(), 1); map.insert("help-button".into(), 1); map.insert("main-content".into(), 1); - map.insert("crate-search".into(), 1); map.insert("toggle-all-docs".into(), 1); map.insert("all-types".into(), 1); map.insert("default-settings".into(), 1); diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index ae7d8c108d3..09c54969ef1 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -2773,11 +2773,10 @@ fn render_call_locations(w: &mut Buffer, cx: &mut Context<'_>, item: &clean::Ite sources::print_src( w, contents_subset, - call_data.edition, file_span, cx, &root_path, - Some(highlight::DecorationInfo(decoration_info)), + highlight::DecorationInfo(decoration_info), sources::SourceContext::Embedded { offset: line_min }, ); write!(w, "</div></div>"); diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index 99cf4291927..6d0a825fec8 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -1322,17 +1322,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean:: fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) { wrap_into_docblock(w, |w| { - highlight::render_with_highlighting( - &t.source, - w, - Some("macro"), - None, - None, - it.span(cx.tcx()).inner().edition(), - None, - None, - None, - ); + highlight::render_macro_with_highlighting(&t.source, w); }); document(w, cx, it, None, HeadingOffset::H2) } diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 6fb41ff3279..f9abb46207d 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -1,5 +1,4 @@ use std::ffi::OsStr; -use std::fmt::Write; use std::fs::{self, File}; use std::io::prelude::*; use std::io::{self, BufReader}; @@ -10,7 +9,8 @@ use std::sync::LazyLock as Lazy; use itertools::Itertools; use rustc_data_structures::flock; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use serde::Serialize; +use serde::ser::SerializeSeq; +use serde::{Serialize, Serializer}; use super::{collect_paths_for_type, ensure_trailing_slash, Context, BASIC_KEYWORDS}; use crate::clean::Crate; @@ -284,25 +284,43 @@ pub(super) fn write_shared( cx.write_shared(SharedResource::Unversioned { name }, contents, &options.emit)?; } - fn collect(path: &Path, krate: &str, key: &str) -> io::Result<(Vec<String>, Vec<String>)> { + /// Read a file and return all lines that match the `"{crate}":{data},` format, + /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`. + /// + /// This forms the payload of files that look like this: + /// + /// ```javascript + /// var data = { + /// "{crate1}":{data}, + /// "{crate2}":{data} + /// }; + /// use_data(data); + /// ``` + /// + /// The file needs to be formatted so that *only crate data lines start with `"`*. + fn collect(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> { let mut ret = Vec::new(); let mut krates = Vec::new(); if path.exists() { - let prefix = format!(r#"{}["{}"]"#, key, krate); + let prefix = format!("\"{}\"", krate); for line in BufReader::new(File::open(path)?).lines() { let line = line?; - if !line.starts_with(key) { + if !line.starts_with('"') { continue; } if line.starts_with(&prefix) { continue; } - ret.push(line.to_string()); + if line.ends_with(",") { + ret.push(line[..line.len() - 1].to_string()); + } else { + // No comma (it's the case for the last added crate line) + ret.push(line.to_string()); + } krates.push( - line[key.len() + 2..] - .split('"') - .next() + line.split('"') + .find(|s| !s.is_empty()) .map(|s| s.to_owned()) .unwrap_or_else(String::new), ); @@ -311,6 +329,20 @@ pub(super) fn write_shared( Ok((ret, krates)) } + /// Read a file and return all lines that match the <code>"{crate}":{data},\</code> format, + /// and return a tuple `(Vec<DataString>, Vec<CrateNameString>)`. + /// + /// This forms the payload of files that look like this: + /// + /// ```javascript + /// var data = JSON.parse('{\ + /// "{crate1}":{data},\ + /// "{crate2}":{data}\ + /// }'); + /// use_data(data); + /// ``` + /// + /// The file needs to be formatted so that *only crate data lines start with `"`*. fn collect_json(path: &Path, krate: &str) -> io::Result<(Vec<String>, Vec<String>)> { let mut ret = Vec::new(); let mut krates = Vec::new(); @@ -526,13 +558,27 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; }, }; - #[derive(Serialize)] struct Implementor { text: String, synthetic: bool, types: Vec<String>, } + impl Serialize for Implementor { + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(None)?; + seq.serialize_element(&self.text)?; + if self.synthetic { + seq.serialize_element(&1)?; + seq.serialize_element(&self.types)?; + } + seq.end() + } + } + let implementors = imps .iter() .filter_map(|imp| { @@ -563,9 +609,9 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; } let implementors = format!( - r#"implementors["{}"] = {};"#, + r#""{}":{}"#, krate.name(cx.tcx()), - serde_json::to_string(&implementors).unwrap() + serde_json::to_string(&implementors).expect("failed serde conversion"), ); let mut mydst = dst.clone(); @@ -576,16 +622,15 @@ if (typeof exports !== 'undefined') {exports.searchIndex = searchIndex}; mydst.push(&format!("{}.{}.js", remote_item_type, remote_path[remote_path.len() - 1])); let (mut all_implementors, _) = - try_err!(collect(&mydst, krate.name(cx.tcx()).as_str(), "implementors"), &mydst); + try_err!(collect(&mydst, krate.name(cx.tcx()).as_str()), &mydst); all_implementors.push(implementors); // Sort the implementors by crate so the file will be generated // identically even with rustdoc running in parallel. all_implementors.sort(); - let mut v = String::from("(function() {var implementors = {};\n"); - for implementor in &all_implementors { - writeln!(v, "{}", *implementor).unwrap(); - } + let mut v = String::from("(function() {var implementors = {\n"); + v.push_str(&all_implementors.join(",\n")); + v.push_str("\n};"); v.push_str( "if (window.register_implementors) {\ window.register_implementors(implementors);\ diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index d0fd637ba88..f508808a8b6 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -11,7 +11,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_session::Session; -use rustc_span::edition::Edition; use rustc_span::source_map::FileName; use std::ffi::OsStr; @@ -213,11 +212,10 @@ impl SourceCollector<'_, '_> { print_src( buf, contents, - cx.shared.edition(), file_span, cx, &root_path, - None, + highlight::DecorationInfo::default(), SourceContext::Standalone, ) }, @@ -266,11 +264,10 @@ pub(crate) enum SourceContext { pub(crate) fn print_src( buf: &mut Buffer, s: &str, - edition: Edition, file_span: rustc_span::Span, context: &Context<'_>, root_path: &str, - decoration_info: Option<highlight::DecorationInfo>, + decoration_info: highlight::DecorationInfo, source_context: SourceContext, ) { let lines = s.lines().count(); @@ -289,15 +286,11 @@ pub(crate) fn print_src( } } line_numbers.write_str("</pre>"); - highlight::render_with_highlighting( + highlight::render_source_with_highlighting( s, buf, - None, - None, - None, - edition, - Some(line_numbers), - Some(highlight::HrefContext { context, file_span, root_path }), + line_numbers, + highlight::HrefContext { context, file_span, root_path }, decoration_info, ); } diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 83fe14550cc..710ca3ee7c7 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -947,18 +947,33 @@ table, height: 100%; } .search-results-title { - display: inline; + margin-top: 0; + white-space: nowrap; + /* flex layout allows shrinking the <select> appropriately if it becomes too large */ + display: inline-flex; + max-width: 100%; + /* make things look like in a line, despite the fact that we're using a layout + with boxes (i.e. from the flex layout) */ + align-items: baseline; } -#search-settings { - font-size: 1.5rem; - font-weight: 500; - margin-bottom: 20px; +#crate-search-div { + display: inline-block; + /* ensures that 100% in properties of #crate-search-div:after + are relative to the size of this div */ + position: relative; + /* allows this div (and with it the <select>-element "#crate-search") to be shrunk */ + min-width: 5em; } #crate-search { min-width: 115px; - margin-top: 5px; - padding-left: 0.15em; + padding: 0; + /* keep these two in sync with "@-moz-document url-prefix()" below */ + padding-left: 4px; padding-right: 23px; + /* prevents the <select> from overflowing the containing div in case it's shrunk */ + max-width: 100%; + /* contents can overflow because of max-width limit, then show ellipsis */ + text-overflow: ellipsis; border: 1px solid; border-radius: 4px; outline: none; @@ -966,13 +981,37 @@ table, -moz-appearance: none; -webkit-appearance: none; /* Removes default arrow from firefox */ + text-indent: 0.01px; + background-color: var(--main-background-color); +} +/* cancel stylistic differences in padding in firefox +for "appearance: none"-style (or equivalent) <select>s */ +@-moz-document url-prefix() { + #crate-search { + padding-left: 0px; /* == 4px - 4px */ + padding-right: 19px; /* == 23px - 4px */ + } +} +/* pseudo-element for holding the dropdown-arrow image; needs to be a separate thing +so that we can apply CSS-filters to change the arrow color in themes */ +#crate-search-div::after { + /* lets clicks through! */ + pointer-events: none; + /* completely covers the underlying div */ + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + content: ""; background-repeat: no-repeat; - background-color: transparent; background-size: 20px; - background-position: calc(100% - 1px) 56%; + background-position: calc(100% - 2px) 56%; + /* image is black color, themes should apply a "filter" property to change the color */ background-image: /* AUTOREPLACE: */url("down-arrow.svg"); - max-width: 100%; - text-overflow: ellipsis; +} +#crate-search > option { + font-size: 1rem; } .search-container { margin-top: 4px; diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index c42cac59bd6..39a4dae3348 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -182,7 +182,7 @@ details.rustdoc-toggle > summary::before { filter: invert(100%); } -#crate-search, .search-input { +.search-input { background-color: #141920; border-color: #424c57; } @@ -191,7 +191,17 @@ details.rustdoc-toggle > summary::before { /* Without the `!important`, the border-color is ignored for `<select>`... It cannot be in the group above because `.search-input` has a different border color on hover. */ - border-color: #424c57 !important; + border-color: #5c6773 !important; +} +#crate-search-div::after { + /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ + filter: invert(41%) sepia(12%) saturate(487%) hue-rotate(171deg) brightness(94%) contrast(94%); +} +#crate-search:hover, #crate-search:focus { + border-color: #e0e0e0 !important; +} +#crate-search-div:hover::after, #crate-search-div:focus-within::after { + filter: invert(98%) sepia(12%) saturate(81%) hue-rotate(343deg) brightness(113%) contrast(76%); } .search-input { @@ -203,20 +213,9 @@ details.rustdoc-toggle > summary::before { color: #000; } -/* Created this empty rule to satisfy the theme checks. */ -.stab.empty-impl {} -.stab.must_implement {} - -.stab.unstable, -.stab.deprecated, -.stab.portability, -.stab.empty-impl, -.stab.must_implement { +.stab { color: #c5c5c5; background: #314559 !important; - border-style: none !important; - border-radius: 4px; - padding: 3px 6px 3px 6px; } .stab.portability > code { diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index a550eb1c130..6188e0ac0a9 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -152,7 +152,7 @@ details.rustdoc-toggle > summary::before { filter: invert(100%); } -#crate-search, .search-input { +.search-input { color: #111; background-color: #f0f0f0; border-color: #f0f0f0; @@ -162,7 +162,17 @@ details.rustdoc-toggle > summary::before { /* Without the `!important`, the border-color is ignored for `<select>`... It cannot be in the group above because `.search-input` has a different border color on hover. */ - border-color: #f0f0f0 !important; + border-color: #d2d2d2 !important; +} +#crate-search-div::after { + /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ + filter: invert(94%) sepia(0%) saturate(721%) hue-rotate(255deg) brightness(90%) contrast(90%); +} +#crate-search:hover, #crate-search:focus { + border-color: #2196f3 !important; +} +#crate-search-div:hover::after, #crate-search-div:focus-within::after { + filter: invert(69%) sepia(60%) saturate(6613%) hue-rotate(184deg) brightness(100%) contrast(91%); } .search-input { @@ -173,12 +183,12 @@ details.rustdoc-toggle > summary::before { border-color: #008dfd; } -.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } -.stab.unstable { background: #FFF5D6; border-color: #FFC600; color: #2f2f2f; } -.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; color: #2f2f2f; } -.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; } -.stab.portability { background: #F3DFFF; border-color: #b07bdb; color: #2f2f2f; } -.stab.portability > code { background: none; } +.stab { background: #314559; } + +.stab.portability > code { + color: #e6e1cf; + background: none; +} .rightside, .out-of-band { diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index b751acff152..fba790b6193 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -144,27 +144,32 @@ details.rustdoc-toggle > summary::before { color: #999; } -#crate-search, .search-input { +.search-input { background-color: white; border-color: #e0e0e0; } - #crate-search { /* Without the `!important`, the border-color is ignored for `<select>`... It cannot be in the group above because `.search-input` has a different border color on hover. */ border-color: #e0e0e0 !important; } +#crate-search-div::after { + /* match border-color; uses https://codepen.io/sosuke/pen/Pjoqqp */ + filter: invert(100%) sepia(0%) saturate(4223%) hue-rotate(289deg) brightness(114%) contrast(76%); +} +#crate-search:hover, #crate-search:focus { + border-color: #717171 !important; +} +#crate-search-div:hover::after, #crate-search-div:focus-within::after { + filter: invert(44%) sepia(18%) saturate(23%) hue-rotate(317deg) brightness(96%) contrast(93%); +} .search-input:focus { border-color: #66afe9; } -.stab.empty-impl { background: #FFF5D6; border-color: #FFC600; } -.stab.unstable { background: #FFF5D6; border-color: #FFC600; } -.stab.deprecated { background: #ffc4c4; border-color: #db7b7b; } -.stab.must_implement { background: #F3DFFF; border-color: #b07bdb; } -.stab.portability { background: #F3DFFF; border-color: #b07bdb; } +.stab { background: #FFF5D6; border-color: #FFC600; } .stab.portability > code { background: none; } .rightside, @@ -321,7 +326,7 @@ kbd { .popover, .popover::before, #help-button span.top, #help-button span.bottom { - border-color: #DDDDDD; + border-color: #e0e0e0; } #copy-path { diff --git a/src/librustdoc/html/static/images/down-arrow.svg b/src/librustdoc/html/static/images/down-arrow.svg index 35437e77a71..5d76a64e92c 100644 --- a/src/librustdoc/html/static/images/down-arrow.svg +++ b/src/librustdoc/html/static/images/down-arrow.svg @@ -1 +1 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" width="128" height="128" enable-background="new 0 0 128 128" version="1.1" viewBox="-30 -20 176 176" xml:space="preserve"><g><line x1="111" x2="64" y1="40.5" y2="87.499" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#2F3435" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg> \ No newline at end of file +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="Layer_1" width="128" height="128" enable-background="new 0 0 128 128" version="1.1" viewBox="-30 -20 176 176" xml:space="preserve"><g><line x1="111" x2="64" y1="40.5" y2="87.499" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/><line x1="64" x2="17" y1="87.499" y2="40.5" fill="none" stroke="#000000" stroke-linecap="square" stroke-miterlimit="10" stroke-width="12"/></g></svg> \ No newline at end of file diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 0702b2b0b7c..5dec610b30c 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -348,8 +348,7 @@ function loadCss(cssFileName) { function onHashChange(ev) { // If we're in mobile mode, we should hide the sidebar in any case. - const sidebar = document.getElementsByClassName("sidebar")[0]; - removeClass(sidebar, "shown"); + hideSidebar(); handleHashes(ev); } @@ -501,6 +500,10 @@ function loadCss(cssFileName) { const synthetic_implementors = document.getElementById("synthetic-implementors-list"); const inlined_types = new Set(); + const TEXT_IDX = 0; + const SYNTHETIC_IDX = 1; + const TYPES_IDX = 2; + if (synthetic_implementors) { // This `inlined_types` variable is used to avoid having the same implementation // showing up twice. For example "String" in the "Sync" doc page. @@ -536,10 +539,12 @@ function loadCss(cssFileName) { struct_loop: for (const struct of structs) { - const list = struct.synthetic ? synthetic_implementors : implementors; + const list = struct[SYNTHETIC_IDX] ? synthetic_implementors : implementors; - if (struct.synthetic) { - for (const struct_type of struct.types) { + // The types list is only used for synthetic impls. + // If this changes, `main.js` and `write_shared.rs` both need changed. + if (struct[SYNTHETIC_IDX]) { + for (const struct_type of struct[TYPES_IDX]) { if (inlined_types.has(struct_type)) { continue struct_loop; } @@ -548,7 +553,7 @@ function loadCss(cssFileName) { } const code = document.createElement("h3"); - code.innerHTML = struct.text; + code.innerHTML = struct[TEXT_IDX]; addClass(code, "code-header"); addClass(code, "in-band"); @@ -728,11 +733,50 @@ function loadCss(cssFileName) { }); }()); + let oldSidebarScrollPosition = null; + + function showSidebar() { + if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { + // This is to keep the scroll position on mobile. + oldSidebarScrollPosition = window.scrollY; + document.body.style.width = `${document.body.offsetWidth}px`; + document.body.style.position = "fixed"; + document.body.style.top = `-${oldSidebarScrollPosition}px`; + document.querySelector(".mobile-topbar").style.top = `${oldSidebarScrollPosition}px`; + document.querySelector(".mobile-topbar").style.position = "relative"; + } else { + oldSidebarScrollPosition = null; + } + const sidebar = document.getElementsByClassName("sidebar")[0]; + addClass(sidebar, "shown"); + } + function hideSidebar() { + if (oldSidebarScrollPosition !== null) { + // This is to keep the scroll position on mobile. + document.body.style.width = ""; + document.body.style.position = ""; + document.body.style.top = ""; + document.querySelector(".mobile-topbar").style.top = ""; + document.querySelector(".mobile-topbar").style.position = ""; + // The scroll position is lost when resetting the style, hence why we store it in + // `oldSidebarScrollPosition`. + window.scrollTo(0, oldSidebarScrollPosition); + oldSidebarScrollPosition = null; + } const sidebar = document.getElementsByClassName("sidebar")[0]; removeClass(sidebar, "shown"); } + window.addEventListener("resize", () => { + if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT && + oldSidebarScrollPosition !== null) { + // If the user opens the sidebar in "mobile" mode, and then grows the browser window, + // we need to switch away from mobile mode and make the main content area scrollable. + hideSidebar(); + } + }); + function handleClick(id, f) { const elem = document.getElementById(id); if (elem) { @@ -775,9 +819,9 @@ function loadCss(cssFileName) { sidebar_menu_toggle.addEventListener("click", () => { const sidebar = document.getElementsByClassName("sidebar")[0]; if (!hasClass(sidebar, "shown")) { - addClass(sidebar, "shown"); + showSidebar(); } else { - removeClass(sidebar, "shown"); + hideSidebar(); } }); } diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 75c7bd45a29..d04ec357c40 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -429,9 +429,9 @@ function initSearch(rawSearchIndex) { } const posBefore = parserState.pos; getNextElem(query, parserState, elems, endChar === ">"); - // This case can be encountered if `getNextElem` encounted a "stop character" right from - // the start. For example if you have `,,` or `<>`. In this case, we simply move up the - // current position to continue the parsing. + // This case can be encountered if `getNextElem` encountered a "stop character" right + // from the start. For example if you have `,,` or `<>`. In this case, we simply move up + // the current position to continue the parsing. if (posBefore === parserState.pos) { parserState.pos += 1; } @@ -581,7 +581,7 @@ function initSearch(rawSearchIndex) { const elem = document.getElementById("crate-search"); if (elem && - elem.value !== "All crates" && + elem.value !== "all crates" && hasOwnPropertyRustdoc(rawSearchIndex, elem.value) ) { return elem.value; @@ -1551,12 +1551,6 @@ function initSearch(rawSearchIndex) { return [displayPath, href]; } - function escape(content) { - const h1 = document.createElement("h1"); - h1.textContent = content; - return h1.innerHTML; - } - function pathSplitter(path) { const tmp = "<span>" + path.replace(/::/g, "::</span><span>"); if (tmp.endsWith("<span>")) { @@ -1710,22 +1704,15 @@ function initSearch(rawSearchIndex) { let crates = ""; const crates_list = Object.keys(rawSearchIndex); if (crates_list.length > 1) { - crates = " in <select id=\"crate-search\"><option value=\"All crates\">" + - "All crates</option>"; + crates = " in <div id=\"crate-search-div\"><select id=\"crate-search\">" + + "<option value=\"all crates\">all crates</option>"; for (const c of crates_list) { crates += `<option value="${c}" ${c === filterCrates && "selected"}>${c}</option>`; } - crates += "</select>"; - } - - let typeFilter = ""; - if (results.query.typeFilter !== NO_TYPE_FILTER) { - typeFilter = " (type: " + escape(itemTypes[results.query.typeFilter]) + ")"; + crates += "</select></div>"; } - let output = "<div id=\"search-settings\">" + - `<h1 class="search-results-title">Results for ${escape(results.query.userQuery)}` + - `${typeFilter}</h1>${crates}</div>`; + let output = `<h1 class="search-results-title">Results${crates}</h1>`; if (results.query.error !== null) { output += `<h3>Query parser error: "${results.query.error}".</h3>`; output += "<div id=\"titles\">" + @@ -2245,7 +2232,7 @@ function initSearch(rawSearchIndex) { } function updateCrate(ev) { - if (ev.target.value === "All crates") { + if (ev.target.value === "all crates") { // If we don't remove it from the URL, it'll be picked up again by the search. const params = searchState.getQueryStringParams(); const query = searchState.input.value.trim(); diff --git a/src/librustdoc/html/static/js/source-script.js b/src/librustdoc/html/static/js/source-script.js index c45d614293a..06d15d9e5ff 100644 --- a/src/librustdoc/html/static/js/source-script.js +++ b/src/librustdoc/html/static/js/source-script.js @@ -10,7 +10,7 @@ (function() { const rootPath = document.getElementById("rustdoc-vars").attributes["data-root-path"].value; -let oldScrollPosition = 0; +let oldScrollPosition = null; const NAME_OFFSET = 0; const DIRS_OFFSET = 1; @@ -75,18 +75,21 @@ function toggleSidebar() { oldScrollPosition = window.scrollY; document.body.style.position = "fixed"; document.body.style.top = `-${oldScrollPosition}px`; + } else { + oldScrollPosition = null; } addClass(document.documentElement, "source-sidebar-expanded"); child.innerText = "<"; updateLocalStorage("source-sidebar-show", "true"); } else { - if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT) { + if (window.innerWidth < window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) { // This is to keep the scroll position on mobile. document.body.style.position = ""; document.body.style.top = ""; // The scroll position is lost when resetting the style, hence why we store it in - // `oldScroll`. + // `oldScrollPosition`. window.scrollTo(0, oldScrollPosition); + oldScrollPosition = null; } removeClass(document.documentElement, "source-sidebar-expanded"); child.innerText = ">"; @@ -94,6 +97,17 @@ function toggleSidebar() { } } +window.addEventListener("resize", () => { + if (window.innerWidth >= window.RUSTDOC_MOBILE_BREAKPOINT && oldScrollPosition !== null) { + // If the user opens the sidebar in "mobile" mode, and then grows the browser window, + // we need to switch away from mobile mode and make the main content area scrollable. + document.body.style.position = ""; + document.body.style.top = ""; + window.scrollTo(0, oldScrollPosition); + oldScrollPosition = null; + } +}); + function createSidebarToggle() { const sidebarToggle = document.createElement("div"); sidebarToggle.id = "sidebar-toggle"; diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index 8caba8cb902..4c21fd55328 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -685,24 +685,18 @@ impl FromWithTcx<clean::Variant> for Variant { impl FromWithTcx<clean::Import> for Import { fn from_tcx(import: clean::Import, tcx: TyCtxt<'_>) -> Self { use clean::ImportKind::*; - match import.kind { - Simple(s) => Import { - source: import.source.path.whole_name(), - name: s.to_string(), - id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)), - glob: false, - }, - Glob => Import { - source: import.source.path.whole_name(), - name: import - .source - .path - .last_opt() - .unwrap_or_else(|| Symbol::intern("*")) - .to_string(), - id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)), - glob: true, - }, + let (name, glob) = match import.kind { + Simple(s) => (s.to_string(), false), + Glob => ( + import.source.path.last_opt().unwrap_or_else(|| Symbol::intern("*")).to_string(), + true, + ), + }; + Import { + source: import.source.path.whole_name(), + name, + id: import.source.did.map(ItemId::from).map(|i| from_item_id(i, tcx)), + glob, } } } diff --git a/src/librustdoc/passes/strip_hidden.rs b/src/librustdoc/passes/strip_hidden.rs index 533e2ce46dd..9914edf3036 100644 --- a/src/librustdoc/passes/strip_hidden.rs +++ b/src/librustdoc/passes/strip_hidden.rs @@ -17,6 +17,7 @@ pub(crate) const STRIP_HIDDEN: Pass = Pass { /// Strip items marked `#[doc(hidden)]` pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { let mut retained = ItemIdSet::default(); + let is_json_output = cx.output_format.is_json() && !cx.show_coverage; // strip all #[doc(hidden)] items let krate = { @@ -25,7 +26,12 @@ pub(crate) fn strip_hidden(krate: clean::Crate, cx: &mut DocContext<'_>) -> clea }; // strip all impls referencing stripped items - let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache }; + let mut stripper = ImplStripper { + retained: &retained, + cache: &cx.cache, + is_json_output, + document_private: cx.render_options.document_private, + }; stripper.fold_crate(krate) } diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index 9ba841a31cf..f3aa3c7ce24 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -17,6 +17,7 @@ pub(crate) const STRIP_PRIVATE: Pass = Pass { pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> clean::Crate { // This stripper collects all *retained* nodes. let mut retained = ItemIdSet::default(); + let is_json_output = cx.output_format.is_json() && !cx.show_coverage; // strip all private items { @@ -24,12 +25,17 @@ pub(crate) fn strip_private(mut krate: clean::Crate, cx: &mut DocContext<'_>) -> retained: &mut retained, access_levels: &cx.cache.access_levels, update_retained: true, - is_json_output: cx.output_format.is_json() && !cx.show_coverage, + is_json_output, }; krate = ImportStripper.fold_crate(stripper.fold_crate(krate)); } // strip all impls referencing private items - let mut stripper = ImplStripper { retained: &retained, cache: &cx.cache }; + let mut stripper = ImplStripper { + retained: &retained, + cache: &cx.cache, + is_json_output, + document_private: cx.render_options.document_private, + }; stripper.fold_crate(krate) } diff --git a/src/librustdoc/passes/stripper.rs b/src/librustdoc/passes/stripper.rs index 0d419042a10..3f069e8393f 100644 --- a/src/librustdoc/passes/stripper.rs +++ b/src/librustdoc/passes/stripper.rs @@ -14,17 +14,19 @@ pub(crate) struct Stripper<'a> { pub(crate) is_json_output: bool, } -impl<'a> Stripper<'a> { - // We need to handle this differently for the JSON output because some non exported items could - // be used in public API. And so, we need these items as well. `is_exported` only checks if they - // are in the public API, which is not enough. - #[inline] - fn is_item_reachable(&self, item_id: ItemId) -> bool { - if self.is_json_output { - self.access_levels.is_reachable(item_id.expect_def_id()) - } else { - self.access_levels.is_exported(item_id.expect_def_id()) - } +// We need to handle this differently for the JSON output because some non exported items could +// be used in public API. And so, we need these items as well. `is_exported` only checks if they +// are in the public API, which is not enough. +#[inline] +fn is_item_reachable( + is_json_output: bool, + access_levels: &AccessLevels<DefId>, + item_id: ItemId, +) -> bool { + if is_json_output { + access_levels.is_reachable(item_id.expect_def_id()) + } else { + access_levels.is_exported(item_id.expect_def_id()) } } @@ -61,7 +63,9 @@ impl<'a> DocFolder for Stripper<'a> { | clean::MacroItem(..) | clean::ForeignTypeItem => { let item_id = i.item_id; - if item_id.is_local() && !self.is_item_reachable(item_id) { + if item_id.is_local() + && !is_item_reachable(self.is_json_output, self.access_levels, item_id) + { debug!("Stripper: stripping {:?} {:?}", i.type_(), i.name); return None; } @@ -133,6 +137,8 @@ impl<'a> DocFolder for Stripper<'a> { pub(crate) struct ImplStripper<'a> { pub(crate) retained: &'a ItemIdSet, pub(crate) cache: &'a Cache, + pub(crate) is_json_output: bool, + pub(crate) document_private: bool, } impl<'a> DocFolder for ImplStripper<'a> { @@ -140,8 +146,27 @@ impl<'a> DocFolder for ImplStripper<'a> { if let clean::ImplItem(ref imp) = *i.kind { // Impl blocks can be skipped if they are: empty; not a trait impl; and have no // documentation. - if imp.trait_.is_none() && imp.items.is_empty() && i.doc_value().is_none() { - return None; + // + // There is one special case: if the impl block contains only private items. + if imp.trait_.is_none() { + // If the only items present are private ones and we're not rendering private items, + // we don't document it. + if !imp.items.is_empty() + && !self.document_private + && imp.items.iter().all(|i| { + let item_id = i.item_id; + item_id.is_local() + && !is_item_reachable( + self.is_json_output, + &self.cache.access_levels, + item_id, + ) + }) + { + return None; + } else if imp.items.is_empty() && i.doc_value().is_none() { + return None; + } } if let Some(did) = imp.for_.def_id(self.cache) { if did.is_local() && !imp.for_.is_assoc_ty() && !self.retained.contains(&did.into()) diff --git a/src/llvm-project b/src/llvm-project -Subproject 8b6b5014fdad3a750f7242a6bfdcad83619498d +Subproject e3be3f64ecac101d14ceda759ba078ad0aaf374 diff --git a/src/rustdoc-json-types/lib.rs b/src/rustdoc-json-types/lib.rs index bd4ea98441d..ecdecadd2ef 100644 --- a/src/rustdoc-json-types/lib.rs +++ b/src/rustdoc-json-types/lib.rs @@ -591,8 +591,11 @@ pub struct Import { /// May be different from the last segment of `source` when renaming imports: /// `use source as name;` pub name: String, - /// The ID of the item being imported. - pub id: Option<Id>, // FIXME is this actually ever None? + /// The ID of the item being imported. Will be `None` in case of re-exports of primitives: + /// ```rust + /// pub use i32 as my_i32; + /// ``` + pub id: Option<Id>, /// Whether this import uses a glob: `use source::*;` pub glob: bool, } diff --git a/src/test/codegen/layout-size-checks.rs b/src/test/codegen/layout-size-checks.rs new file mode 100644 index 00000000000..d067cc10a94 --- /dev/null +++ b/src/test/codegen/layout-size-checks.rs @@ -0,0 +1,31 @@ +// compile-flags: -O +// only-x86_64 +// ignore-debug: the debug assertions get in the way + +#![crate_type = "lib"] + +use std::alloc::Layout; + +type RGB48 = [u16; 3]; + +// CHECK-LABEL: @layout_array_rgb48 +#[no_mangle] +pub fn layout_array_rgb48(n: usize) -> Layout { + // CHECK-NOT: llvm.umul.with.overflow.i64 + // CHECK: icmp ugt i64 %n, 1537228672809129301 + // CHECK-NOT: llvm.umul.with.overflow.i64 + // CHECK: mul nuw nsw i64 %n, 6 + // CHECK-NOT: llvm.umul.with.overflow.i64 + Layout::array::<RGB48>(n).unwrap() +} + +// CHECK-LABEL: @layout_array_i32 +#[no_mangle] +pub fn layout_array_i32(n: usize) -> Layout { + // CHECK-NOT: llvm.umul.with.overflow.i64 + // CHECK: icmp ugt i64 %n, 2305843009213693951 + // CHECK-NOT: llvm.umul.with.overflow.i64 + // CHECK: shl nuw nsw i64 %n, 2 + // CHECK-NOT: llvm.umul.with.overflow.i64 + Layout::array::<i32>(n).unwrap() +} diff --git a/src/test/mir-opt/README.md b/src/test/mir-opt/README.md index a0550466cf0..0721d9f7019 100644 --- a/src/test/mir-opt/README.md +++ b/src/test/mir-opt/README.md @@ -14,6 +14,18 @@ presence of pointers in constants or other bit width dependent things. In that c to your test, causing separate files to be generated for 32bit and 64bit systems. +## Unit testing + +If you are only testing the behavior of a particular mir-opt pass on some specific input (as is +usually the case), you should add + +``` +// unit-test: PassName +``` + +to the top of the file. This makes sure that other passes don't run which means you'll get the input +you expected and your test won't break when other code changes. + ## Emit a diff of the mir for a specific optimization This is what you want most often when you want to see how an optimization changes the MIR. diff --git a/src/test/mir-opt/bool_compare.rs b/src/test/mir-opt/bool_compare.rs index 3ff046325dc..4435bf5b0f2 100644 --- a/src/test/mir-opt/bool_compare.rs +++ b/src/test/mir-opt/bool_compare.rs @@ -1,3 +1,5 @@ +// unit-test: InstCombine + // EMIT_MIR bool_compare.opt1.InstCombine.diff fn opt1(x: bool) -> u32 { if x != true { 0 } else { 1 } diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff b/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff deleted file mode 100644 index c73150f947d..00000000000 --- a/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff +++ /dev/null @@ -1,77 +0,0 @@ -- // MIR for `norm2` before InstCombine -+ // MIR for `norm2` after InstCombine - - fn norm2(_1: [f32; 2]) -> f32 { - debug x => _1; // in scope 0 at $DIR/combine_array_len.rs:+0:10: +0:11 - let mut _0: f32; // return place in scope 0 at $DIR/combine_array_len.rs:+0:26: +0:29 - let _2: f32; // in scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10 - let _3: usize; // in scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16 - let mut _4: usize; // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - let mut _5: bool; // in scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - let _7: usize; // in scope 0 at $DIR/combine_array_len.rs:+2:15: +2:16 - let mut _8: usize; // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17 - let mut _9: bool; // in scope 0 at $DIR/combine_array_len.rs:+2:13: +2:17 - let mut _10: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:8 - let mut _11: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:5: +3:6 - let mut _12: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:7: +3:8 - let mut _13: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:14 - let mut _14: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:11: +3:12 - let mut _15: f32; // in scope 0 at $DIR/combine_array_len.rs:+3:13: +3:14 - scope 1 { - debug a => _2; // in scope 1 at $DIR/combine_array_len.rs:+1:9: +1:10 - let _6: f32; // in scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10 - scope 2 { - debug b => _6; // in scope 2 at $DIR/combine_array_len.rs:+2:9: +2:10 - } - } - - bb0: { - StorageLive(_2); // scope 0 at $DIR/combine_array_len.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16 - _3 = const 0_usize; // scope 0 at $DIR/combine_array_len.rs:+1:15: +1:16 -- _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 -+ _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - _5 = Lt(_3, _4); // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - } - - bb1: { - _2 = _1[_3]; // scope 0 at $DIR/combine_array_len.rs:+1:13: +1:17 - StorageDead(_3); // scope 0 at $DIR/combine_array_len.rs:+1:17: +1:18 - StorageLive(_6); // scope 1 at $DIR/combine_array_len.rs:+2:9: +2:10 - StorageLive(_7); // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16 - _7 = const 1_usize; // scope 1 at $DIR/combine_array_len.rs:+2:15: +2:16 -- _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 -+ _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 - _9 = Lt(_7, _8); // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 - assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 - } - - bb2: { - _6 = _1[_7]; // scope 1 at $DIR/combine_array_len.rs:+2:13: +2:17 - StorageDead(_7); // scope 1 at $DIR/combine_array_len.rs:+2:17: +2:18 - StorageLive(_10); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8 - StorageLive(_11); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6 - _11 = _2; // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:6 - StorageLive(_12); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8 - _12 = _2; // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8 - _10 = Mul(move _11, move _12); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:8 - StorageDead(_12); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8 - StorageDead(_11); // scope 2 at $DIR/combine_array_len.rs:+3:7: +3:8 - StorageLive(_13); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14 - StorageLive(_14); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12 - _14 = _6; // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:12 - StorageLive(_15); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - _15 = _6; // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - _13 = Mul(move _14, move _15); // scope 2 at $DIR/combine_array_len.rs:+3:11: +3:14 - StorageDead(_15); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - StorageDead(_14); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - _0 = Add(move _10, move _13); // scope 2 at $DIR/combine_array_len.rs:+3:5: +3:14 - StorageDead(_13); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - StorageDead(_10); // scope 2 at $DIR/combine_array_len.rs:+3:13: +3:14 - StorageDead(_6); // scope 1 at $DIR/combine_array_len.rs:+4:1: +4:2 - StorageDead(_2); // scope 0 at $DIR/combine_array_len.rs:+4:1: +4:2 - return; // scope 0 at $DIR/combine_array_len.rs:+4:2: +4:2 - } - } - diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff b/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff index c73150f947d..c73150f947d 100644 --- a/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff +++ b/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff diff --git a/src/test/mir-opt/combine_array_len.rs b/src/test/mir-opt/combine_array_len.rs index 93490c14fd6..3ef3bd09afd 100644 --- a/src/test/mir-opt/combine_array_len.rs +++ b/src/test/mir-opt/combine_array_len.rs @@ -1,4 +1,4 @@ -// EMIT_MIR_FOR_EACH_BIT_WIDTH +// unit-test: InstCombine // EMIT_MIR combine_array_len.norm2.InstCombine.diff fn norm2(x: [f32; 2]) -> f32 { diff --git a/src/test/mir-opt/const_goto.rs b/src/test/mir-opt/const_goto.rs index 939902e70e9..6f84f186b31 100644 --- a/src/test/mir-opt/const_goto.rs +++ b/src/test/mir-opt/const_goto.rs @@ -1,3 +1,5 @@ +// unit-test: ConstGoto + pub enum Foo { A, B, diff --git a/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff b/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff index 2b09ef78661..81c356cb1db 100644 --- a/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff +++ b/src/test/mir-opt/const_goto_storage.match_nested_if.ConstGoto.diff @@ -17,7 +17,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/const_goto_storage.rs:+1:9: +1:12 - StorageLive(_2); // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23 -- nop; // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23 +- Deinit(_2); // scope 0 at $DIR/const_goto_storage.rs:+1:21: +1:23 - StorageLive(_3); // scope 0 at $DIR/const_goto_storage.rs:+2:15: +6:10 - StorageLive(_4); // scope 0 at $DIR/const_goto_storage.rs:+2:18: +2:76 - StorageLive(_5); // scope 0 at $DIR/const_goto_storage.rs:+2:21: +2:52 diff --git a/src/test/mir-opt/const_goto_storage.rs b/src/test/mir-opt/const_goto_storage.rs index 4ef68e7e1fa..459599c73eb 100644 --- a/src/test/mir-opt/const_goto_storage.rs +++ b/src/test/mir-opt/const_goto_storage.rs @@ -1,3 +1,5 @@ +// unit-test: ConstGoto + // EMIT_MIR const_goto_storage.match_nested_if.ConstGoto.diff fn match_nested_if() -> bool { let val = match () { diff --git a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff index f2d4bee1bf9..73fdf140498 100644 --- a/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/boxes.main.ConstProp.diff @@ -12,8 +12,6 @@ let mut _7: std::boxed::Box<i32>; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 let mut _8: *const i32; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 let mut _9: *const i32; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 - let mut _10: *const i32; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 - let mut _11: *const i32; // in scope 0 at $DIR/boxes.rs:+1:14: +1:22 scope 1 { debug x => _1; // in scope 1 at $DIR/boxes.rs:+1:9: +1:10 } diff --git a/src/test/mir-opt/deaggregator_test.rs b/src/test/mir-opt/deaggregator_test.rs index 342e222431b..ee59402af38 100644 --- a/src/test/mir-opt/deaggregator_test.rs +++ b/src/test/mir-opt/deaggregator_test.rs @@ -1,3 +1,5 @@ +// unit-test: Deaggregator + struct Baz { x: usize, y: f32, diff --git a/src/test/mir-opt/deaggregator_test_enum.rs b/src/test/mir-opt/deaggregator_test_enum.rs index 02b63a1f55d..ea402dafdec 100644 --- a/src/test/mir-opt/deaggregator_test_enum.rs +++ b/src/test/mir-opt/deaggregator_test_enum.rs @@ -1,3 +1,5 @@ +// unit-test: Deaggregator + enum Baz { Empty, Foo { x: usize }, diff --git a/src/test/mir-opt/deaggregator_test_enum_2.rs b/src/test/mir-opt/deaggregator_test_enum_2.rs index 489854ff0aa..955c317324a 100644 --- a/src/test/mir-opt/deaggregator_test_enum_2.rs +++ b/src/test/mir-opt/deaggregator_test_enum_2.rs @@ -1,3 +1,4 @@ +// unit-test: Deaggregator // Test that deaggregate fires in more than one basic block enum Foo { diff --git a/src/test/mir-opt/deaggregator_test_multiple.rs b/src/test/mir-opt/deaggregator_test_multiple.rs index 9730b9aa8e5..46305fe21d2 100644 --- a/src/test/mir-opt/deaggregator_test_multiple.rs +++ b/src/test/mir-opt/deaggregator_test_multiple.rs @@ -1,3 +1,4 @@ +// unit-test: Deaggregator // Test that deaggregate fires more than once per block enum Foo { diff --git a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff index 01864ba24ac..53f977de5d6 100644 --- a/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff +++ b/src/test/mir-opt/deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff @@ -7,101 +7,94 @@ let mut _2: &[u8]; // in scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23 let mut _3: &str; // in scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23 let mut _4: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 - let mut _5: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 - let mut _6: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 - let mut _7: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 - scope 1 (inlined core::str::<impl str>::as_bytes) { // at $DIR/deduplicate_blocks.rs:3:11: 3:23 - debug self => _3; // in scope 1 at $SRC_DIR/core/src/str/mod.rs:LL:COL - let mut _8: &str; // in scope 1 at $SRC_DIR/core/src/str/mod.rs:LL:COL - scope 2 { - } - } + let mut _5: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 + let mut _6: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 + let mut _7: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 + let mut _8: usize; // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 + let mut _9: bool; // in scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 bb0: { StorageLive(_2); // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23 StorageLive(_3); // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23 - _3 = _1; // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23 - StorageLive(_8); // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL - _8 = _3; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL -- _2 = transmute::<&str, &[u8]>(move _8) -> bb14; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL -+ _2 = transmute::<&str, &[u8]>(move _8) -> bb12; // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL + _3 = &(*_1); // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23 + _2 = core::str::<impl str>::as_bytes(move _3) -> bb1; // scope 0 at $DIR/deduplicate_blocks.rs:+1:11: +1:23 // mir::Constant - // + span: $SRC_DIR/core/src/str/mod.rs:LL:COL - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&str) -> &[u8] {transmute::<&str, &[u8]>}, val: Value(<ZST>) } + // + span: $DIR/deduplicate_blocks.rs:5:13: 5:21 + // + literal: Const { ty: for<'r> fn(&'r str) -> &'r [u8] {core::str::<impl str>::as_bytes}, val: Value(<ZST>) } } bb1: { - switchInt((*_2)[0 of 4]) -> [47_u8: bb2, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + StorageDead(_3); // scope 0 at $DIR/deduplicate_blocks.rs:+1:22: +1:23 + _7 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 + _8 = const 4_usize; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 + _9 = Ge(move _7, move _8); // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 + switchInt(move _9) -> [false: bb6, otherwise: bb2]; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 } bb2: { - switchInt((*_2)[1 of 4]) -> [47_u8: bb3, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + switchInt((*_2)[0 of 4]) -> [47_u8: bb3, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 } bb3: { - switchInt((*_2)[2 of 4]) -> [47_u8: bb4, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + switchInt((*_2)[1 of 4]) -> [47_u8: bb4, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 } bb4: { -- switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 -+ switchInt((*_2)[3 of 4]) -> [47_u8: bb9, otherwise: bb5]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + switchInt((*_2)[2 of 4]) -> [47_u8: bb5, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 } bb5: { - _4 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 - _5 = Ge(move _4, const 3_usize); // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 - switchInt(move _5) -> [false: bb9, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 +- switchInt((*_2)[3 of 4]) -> [47_u8: bb11, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 ++ switchInt((*_2)[3 of 4]) -> [47_u8: bb10, otherwise: bb6]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 } bb6: { - switchInt((*_2)[0 of 3]) -> [47_u8: bb7, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + _4 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 + _5 = const 3_usize; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 + _6 = Ge(move _4, move _5); // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 + switchInt(move _6) -> [false: bb10, otherwise: bb7]; // scope 0 at $DIR/deduplicate_blocks.rs:+3:9: +3:31 } bb7: { - switchInt((*_2)[1 of 3]) -> [47_u8: bb8, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + switchInt((*_2)[0 of 3]) -> [47_u8: bb8, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 } bb8: { -- switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb12, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 -+ switchInt((*_2)[2 of 3]) -> [47_u8: bb10, 33_u8: bb10, otherwise: bb9]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + switchInt((*_2)[1 of 3]) -> [47_u8: bb9, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 } bb9: { +- switchInt((*_2)[2 of 3]) -> [47_u8: bb12, 33_u8: bb13, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 ++ switchInt((*_2)[2 of 3]) -> [47_u8: bb11, 33_u8: bb11, otherwise: bb10]; // scope 0 at $DIR/deduplicate_blocks.rs:+1:5: +1:23 + } + + bb10: { - _0 = const false; // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19 -- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19 +- goto -> bb14; // scope 0 at $DIR/deduplicate_blocks.rs:+5:14: +5:19 - } - -- bb10: { +- bb11: { _0 = const false; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46 -- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46 -+ goto -> bb11; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46 +- goto -> bb14; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46 ++ goto -> bb12; // scope 0 at $DIR/deduplicate_blocks.rs:+2:41: +2:46 } -- bb11: { +- bb12: { - _0 = const true; // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39 -- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39 +- goto -> bb14; // scope 0 at $DIR/deduplicate_blocks.rs:+3:35: +3:39 - } - -- bb12: { -+ bb10: { - _0 = const true; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39 -- goto -> bb13; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39 -+ goto -> bb11; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39 - } - - bb13: { + bb11: { - StorageDead(_2); // scope 0 at $DIR/deduplicate_blocks.rs:+7:1: +7:2 - return; // scope 0 at $DIR/deduplicate_blocks.rs:+7:2: +7:2 + _0 = const true; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39 +- goto -> bb14; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39 ++ goto -> bb12; // scope 0 at $DIR/deduplicate_blocks.rs:+4:35: +4:39 } - bb14: { + bb12: { - StorageDead(_8); // scope 2 at $SRC_DIR/core/src/str/mod.rs:LL:COL - StorageDead(_3); // scope 0 at $DIR/deduplicate_blocks.rs:+1:22: +1:23 - _6 = Len((*_2)); // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 - _7 = Ge(move _6, const 4_usize); // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 - switchInt(move _7) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/deduplicate_blocks.rs:+2:9: +2:37 + StorageDead(_2); // scope 0 at $DIR/deduplicate_blocks.rs:+7:1: +7:2 + return; // scope 0 at $DIR/deduplicate_blocks.rs:+7:2: +7:2 } } diff --git a/src/test/mir-opt/deduplicate_blocks.rs b/src/test/mir-opt/deduplicate_blocks.rs index f8f7361dc0d..2b9eed99ecd 100644 --- a/src/test/mir-opt/deduplicate_blocks.rs +++ b/src/test/mir-opt/deduplicate_blocks.rs @@ -1,3 +1,5 @@ +// unit-test: DeduplicateBlocks + // EMIT_MIR deduplicate_blocks.is_line_doc_comment_2.DeduplicateBlocks.diff pub const fn is_line_doc_comment_2(s: &str) -> bool { match s.as_bytes() { diff --git a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff index de0c03bb70b..abd6193fed9 100644 --- a/src/test/mir-opt/derefer_complex_case.main.Derefer.diff +++ b/src/test/mir-opt/derefer_complex_case.main.Derefer.diff @@ -30,12 +30,12 @@ StorageLive(_2); // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 _14 = const main::promoted[0]; // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 // mir::Constant - // + span: $DIR/derefer_complex_case.rs:5:17: 5:26 + // + span: $DIR/derefer_complex_case.rs:6:17: 6:26 // + literal: Const { ty: &[i32; 2], val: Unevaluated(main, [], Some(promoted[0])) } _2 = &(*_14); // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 _1 = <&[i32; 2] as IntoIterator>::into_iter(move _2) -> bb1; // scope 0 at $DIR/derefer_complex_case.rs:+1:17: +1:26 // mir::Constant - // + span: $DIR/derefer_complex_case.rs:5:17: 5:26 + // + span: $DIR/derefer_complex_case.rs:6:17: 6:26 // + literal: Const { ty: fn(&[i32; 2]) -> <&[i32; 2] as IntoIterator>::IntoIter {<&[i32; 2] as IntoIterator>::into_iter}, val: Value(<ZST>) } } @@ -55,7 +55,7 @@ _8 = &mut (*_9); // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 _7 = <std::slice::Iter<i32> as Iterator>::next(move _8) -> bb3; // scope 1 at $DIR/derefer_complex_case.rs:+1:17: +1:26 // mir::Constant - // + span: $DIR/derefer_complex_case.rs:5:17: 5:26 + // + span: $DIR/derefer_complex_case.rs:6:17: 6:26 // + literal: Const { ty: for<'r> fn(&'r mut std::slice::Iter<i32>) -> Option<<std::slice::Iter<i32> as Iterator>::Item> {<std::slice::Iter<i32> as Iterator>::next}, val: Value(<ZST>) } } @@ -76,7 +76,7 @@ _13 = _12; // scope 2 at $DIR/derefer_complex_case.rs:+1:34: +1:37 _6 = std::mem::drop::<i32>(move _13) -> bb7; // scope 2 at $DIR/derefer_complex_case.rs:+1:29: +1:38 // mir::Constant - // + span: $DIR/derefer_complex_case.rs:5:29: 5:33 + // + span: $DIR/derefer_complex_case.rs:6:29: 6:33 // + literal: Const { ty: fn(i32) {std::mem::drop::<i32>}, val: Value(<ZST>) } } diff --git a/src/test/mir-opt/derefer_complex_case.rs b/src/test/mir-opt/derefer_complex_case.rs index 48bec39074c..dc48cee950b 100644 --- a/src/test/mir-opt/derefer_complex_case.rs +++ b/src/test/mir-opt/derefer_complex_case.rs @@ -1,3 +1,4 @@ +// unit-test: Derefer // EMIT_MIR derefer_complex_case.main.Derefer.diff // ignore-wasm32 diff --git a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff index ce6ffaa5641..3540df30836 100644 --- a/src/test/mir-opt/derefer_inline_test.main.Derefer.diff +++ b/src/test/mir-opt/derefer_inline_test.main.Derefer.diff @@ -17,7 +17,7 @@ _3 = AlignOf(std::boxed::Box<u32>); // scope 1 at $DIR/derefer_inline_test.rs:+1:5: +1:12 _4 = alloc::alloc::exchange_malloc(move _2, move _3) -> bb1; // scope 1 at $DIR/derefer_inline_test.rs:+1:5: +1:12 // mir::Constant - // + span: $DIR/derefer_inline_test.rs:10:5: 10:12 + // + span: $DIR/derefer_inline_test.rs:11:5: 11:12 // + literal: Const { ty: unsafe fn(usize, usize) -> *mut u8 {alloc::alloc::exchange_malloc}, val: Value(<ZST>) } } @@ -26,7 +26,7 @@ _5 = ShallowInitBox(move _4, std::boxed::Box<u32>); // scope 0 at $DIR/derefer_inline_test.rs:+1:5: +1:12 (*_5) = f() -> [return: bb2, unwind: bb6]; // scope 0 at $DIR/derefer_inline_test.rs:+1:9: +1:12 // mir::Constant - // + span: $DIR/derefer_inline_test.rs:10:9: 10:10 + // + span: $DIR/derefer_inline_test.rs:11:9: 11:10 // + literal: Const { ty: fn() -> Box<u32> {f}, val: Value(<ZST>) } } diff --git a/src/test/mir-opt/derefer_inline_test.rs b/src/test/mir-opt/derefer_inline_test.rs index 191a8cbbef4..cc06a7dd8c4 100644 --- a/src/test/mir-opt/derefer_inline_test.rs +++ b/src/test/mir-opt/derefer_inline_test.rs @@ -1,3 +1,4 @@ +// unit-test: Derefer // EMIT_MIR derefer_inline_test.main.Derefer.diff // ignore-wasm32 compiled with panic=abort by default diff --git a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff index 0a56ee5e454..ed336208325 100644 --- a/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff +++ b/src/test/mir-opt/derefer_terminator_test.main.Derefer.diff @@ -32,7 +32,7 @@ StorageLive(_1); // scope 0 at $DIR/derefer_terminator_test.rs:+1:9: +1:10 _1 = foo() -> bb1; // scope 0 at $DIR/derefer_terminator_test.rs:+1:13: +1:18 // mir::Constant - // + span: $DIR/derefer_terminator_test.rs:5:13: 5:16 + // + span: $DIR/derefer_terminator_test.rs:6:13: 6:16 // + literal: Const { ty: fn() -> bool {foo}, val: Value(<ZST>) } } @@ -40,7 +40,7 @@ StorageLive(_2); // scope 1 at $DIR/derefer_terminator_test.rs:+2:9: +2:10 _2 = foo() -> bb2; // scope 1 at $DIR/derefer_terminator_test.rs:+2:13: +2:18 // mir::Constant - // + span: $DIR/derefer_terminator_test.rs:6:13: 6:16 + // + span: $DIR/derefer_terminator_test.rs:7:13: 7:16 // + literal: Const { ty: fn() -> bool {foo}, val: Value(<ZST>) } } diff --git a/src/test/mir-opt/derefer_terminator_test.rs b/src/test/mir-opt/derefer_terminator_test.rs index 787b14ae735..d6750c29dd9 100644 --- a/src/test/mir-opt/derefer_terminator_test.rs +++ b/src/test/mir-opt/derefer_terminator_test.rs @@ -1,3 +1,4 @@ +// unit-test: Derefer // EMIT_MIR derefer_terminator_test.main.Derefer.diff // ignore-wasm32 diff --git a/src/test/mir-opt/derefer_test.rs b/src/test/mir-opt/derefer_test.rs index 2ebc0d343bd..fad0fe8eb6f 100644 --- a/src/test/mir-opt/derefer_test.rs +++ b/src/test/mir-opt/derefer_test.rs @@ -1,3 +1,4 @@ +// unit-test: Derefer // EMIT_MIR derefer_test.main.Derefer.diff fn main() { let mut a = (42,43); diff --git a/src/test/mir-opt/derefer_test_multiple.rs b/src/test/mir-opt/derefer_test_multiple.rs index a27363447fe..0b3888b07ab 100644 --- a/src/test/mir-opt/derefer_test_multiple.rs +++ b/src/test/mir-opt/derefer_test_multiple.rs @@ -1,3 +1,4 @@ +// unit-test: Derefer // EMIT_MIR derefer_test_multiple.main.Derefer.diff fn main () { let mut a = (42, 43); diff --git a/src/test/mir-opt/equal_true.rs b/src/test/mir-opt/equal_true.rs index 994cd194a45..717d10c6d76 100644 --- a/src/test/mir-opt/equal_true.rs +++ b/src/test/mir-opt/equal_true.rs @@ -1,3 +1,5 @@ +// unit-test InstCombine + // EMIT_MIR equal_true.opt.InstCombine.diff fn opt(x: bool) -> i32 { diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff index deaba70e082..5dfcd2d54ca 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff @@ -10,15 +10,14 @@ let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _8: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 -+ let mut _9: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 ++ let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 scope 1 { debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11 } scope 2 { } + scope 3 (inlined Vec::<u32>::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ let mut _10: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + } bb0: { @@ -37,10 +36,10 @@ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 - (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ StorageLive(_9); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ _9 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ StorageLive(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ _10 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ StorageLive(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 ++ _8 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 ++ StorageLive(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:33: 8:41 - // + user_ty: UserType(1) @@ -51,11 +50,11 @@ + // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + // + user_ty: UserType(0) + // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) } -+ Deinit((*_9)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ ((*_9).0: alloc::raw_vec::RawVec<u32>) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ ((*_9).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ StorageDead(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ StorageDead(_9); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 ++ Deinit((*_8)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ StorageDead(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ StorageDead(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff index deaba70e082..5dfcd2d54ca 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff @@ -10,15 +10,14 @@ let mut _5: std::boxed::Box<std::vec::Vec<u32>>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 let mut _6: (); // in scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 let mut _7: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 - let mut _8: *const std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 -+ let mut _9: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 ++ let mut _8: &mut std::vec::Vec<u32>; // in scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 scope 1 { debug _x => _1; // in scope 1 at $DIR/inline-into-box-place.rs:+1:9: +1:11 } scope 2 { } + scope 3 (inlined Vec::<u32>::new) { // at $DIR/inline-into-box-place.rs:8:33: 8:43 -+ let mut _10: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ let mut _9: alloc::raw_vec::RawVec<u32>; // in scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + } bb0: { @@ -37,10 +36,10 @@ StorageLive(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 _7 = (((_5.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 - (*_7) = Vec::<u32>::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ StorageLive(_9); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ _9 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 -+ StorageLive(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ _10 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ StorageLive(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 ++ _8 = &mut (*_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 ++ StorageLive(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ _9 = const alloc::raw_vec::RawVec::<u32>::NEW; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL // mir::Constant - // + span: $DIR/inline-into-box-place.rs:8:33: 8:41 - // + user_ty: UserType(1) @@ -51,11 +50,11 @@ + // + span: $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + // + user_ty: UserType(0) + // + literal: Const { ty: alloc::raw_vec::RawVec<u32>, val: Unevaluated(alloc::raw_vec::RawVec::<T>::NEW, [u32], None) } -+ Deinit((*_9)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ ((*_9).0: alloc::raw_vec::RawVec<u32>) = move _10; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ ((*_9).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ StorageDead(_10); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL -+ StorageDead(_9); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 ++ Deinit((*_8)); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ ((*_8).0: alloc::raw_vec::RawVec<u32>) = move _9; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ ((*_8).1: usize) = const 0_usize; // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ StorageDead(_9); // scope 3 at $SRC_DIR/alloc/src/vec/mod.rs:LL:COL ++ StorageDead(_8); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 StorageDead(_7); // scope 0 at $DIR/inline-into-box-place.rs:+1:33: +1:43 _1 = move _5; // scope 0 at $DIR/inline-into-box-place.rs:+1:29: +1:43 StorageDead(_5); // scope 0 at $DIR/inline-into-box-place.rs:+1:42: +1:43 diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff index b78ef36eadd..a3cee3ecf61 100644 --- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff @@ -5,7 +5,7 @@ let mut _0: bool; // return place in scope 0 at /the/src/instrument_coverage.rs:+0:13: +0:17 bb0: { -+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:19:1 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2 ++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:20:1 - 22:2; // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2 _0 = const true; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +1:9 return; // scope 0 at /the/src/instrument_coverage.rs:+2:2: +2:2 } diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index 0490c0df2e6..81d5528231d 100644 --- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -8,12 +8,12 @@ let mut _3: !; // in scope 0 at /the/src/instrument_coverage.rs:+2:18: +4:10 bb0: { -+ Coverage::Counter(1) for /the/src/instrument_coverage.rs:10:1 - 10:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 ++ Coverage::Counter(1) for /the/src/instrument_coverage.rs:11:1 - 11:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 goto -> bb1; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 } bb1: { -+ Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:11:5 - 12:17; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 ++ Coverage::Expression(4294967295) = 1 + 2 for /the/src/instrument_coverage.rs:12:5 - 13:17; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 falseUnwind -> [real: bb2, cleanup: bb6]; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 } @@ -21,7 +21,7 @@ StorageLive(_2); // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17 _2 = bar() -> [return: bb3, unwind: bb6]; // scope 0 at /the/src/instrument_coverage.rs:+2:12: +2:17 // mir::Constant - // + span: /the/src/instrument_coverage.rs:12:12: 12:15 + // + span: /the/src/instrument_coverage.rs:13:12: 13:15 // + literal: Const { ty: fn() -> bool {bar}, val: Value(<ZST>) } } @@ -30,15 +30,15 @@ } bb4: { -+ Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:16:1 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2 -+ Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:13:13 - 13:18; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2 ++ Coverage::Expression(4294967293) = 4294967294 + 0 for /the/src/instrument_coverage.rs:17:1 - 17:2; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2 ++ Coverage::Expression(4294967294) = 4294967295 - 2 for /the/src/instrument_coverage.rs:14:13 - 14:18; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2 _0 = const (); // scope 0 at /the/src/instrument_coverage.rs:+3:13: +3:18 StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:+4:9: +4:10 return; // scope 0 at /the/src/instrument_coverage.rs:+6:2: +6:2 } bb5: { -+ Coverage::Counter(2) for /the/src/instrument_coverage.rs:14:10 - 14:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 ++ Coverage::Counter(2) for /the/src/instrument_coverage.rs:15:10 - 15:11; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 _1 = const (); // scope 0 at /the/src/instrument_coverage.rs:+4:10: +4:10 StorageDead(_2); // scope 0 at /the/src/instrument_coverage.rs:+4:9: +4:10 goto -> bb1; // scope 0 at /the/src/instrument_coverage.rs:+1:5: +5:6 diff --git a/src/test/mir-opt/instrument_coverage.rs b/src/test/mir-opt/instrument_coverage.rs index a748f2c5ccc..7f6a0a0eb09 100644 --- a/src/test/mir-opt/instrument_coverage.rs +++ b/src/test/mir-opt/instrument_coverage.rs @@ -1,6 +1,7 @@ // Test that `-C instrument-coverage` injects Coverage statements. The Coverage Counter statements // are later converted into LLVM instrprof.increment intrinsics, during codegen. +// unit-test: InstrumentCoverage // needs-profiler-support // ignore-windows // compile-flags: -C instrument-coverage --remap-path-prefix={{src-base}}=/the/src diff --git a/src/test/mir-opt/not_equal_false.rs b/src/test/mir-opt/not_equal_false.rs index 5fbb848dcb5..2ae03da40f8 100644 --- a/src/test/mir-opt/not_equal_false.rs +++ b/src/test/mir-opt/not_equal_false.rs @@ -1,3 +1,4 @@ +// unit-test: InstCombine // EMIT_MIR not_equal_false.opt.InstCombine.diff fn opt(x: bool) -> u32 { diff --git a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff index 750aaa88b1c..99667aabdae 100644 --- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff +++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff @@ -23,13 +23,6 @@ scope 3 { debug i => _12; // in scope 3 at $DIR/remove_storage_markers.rs:+2:9: +2:10 } - scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 - debug self => _8; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL - let mut _14: &mut std::ops::Range<i32>; // in scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL - } - } - scope 4 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 - debug self => _3; // in scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL } } @@ -41,29 +34,39 @@ Deinit(_3); // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 (_3.0: i32) = const 0_i32; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 (_3.1: i32) = const 10_i32; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - _2 = move _3; // scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + _2 = <std::ops::Range<i32> as IntoIterator>::into_iter(move _3) -> bb1; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 + // mir::Constant + // + span: $DIR/remove_storage_markers.rs:10:14: 10:19 + // + literal: Const { ty: fn(std::ops::Range<i32>) -> <std::ops::Range<i32> as IntoIterator>::IntoIter {<std::ops::Range<i32> as IntoIterator>::into_iter}, val: Value(<ZST>) } + } + + bb1: { - StorageDead(_3); // scope 1 at $DIR/remove_storage_markers.rs:+2:18: +2:19 - StorageLive(_4); // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 _4 = move _2; // scope 1 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6 + goto -> bb2; // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6 } - bb1: { + bb2: { - StorageLive(_6); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - StorageLive(_7); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - StorageLive(_8); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - StorageLive(_9); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 _9 = &mut _4; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 _8 = &mut (*_9); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 -- StorageLive(_14); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL - _14 = &mut (*_8); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL - _7 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _14) -> bb4; // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL + _7 = <std::ops::Range<i32> as Iterator>::next(move _8) -> bb3; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 // mir::Constant - // + span: $SRC_DIR/core/src/iter/range.rs:LL:COL - // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next}, val: Value(<ZST>) } + // + span: $DIR/remove_storage_markers.rs:10:14: 10:19 + // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> Option<<std::ops::Range<i32> as Iterator>::Item> {<std::ops::Range<i32> as Iterator>::next}, val: Value(<ZST>) } } - bb2: { + bb3: { +- StorageDead(_8); // scope 2 at $DIR/remove_storage_markers.rs:+2:18: +2:19 + _10 = discriminant(_7); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 + switchInt(move _10) -> [0_isize: bb6, 1_isize: bb4, otherwise: bb5]; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 + } + + bb4: { - StorageLive(_12); // scope 2 at $DIR/remove_storage_markers.rs:+2:9: +2:10 _12 = ((_7 as Some).0: i32); // scope 2 at $DIR/remove_storage_markers.rs:+2:9: +2:10 - StorageLive(_13); // scope 3 at $DIR/remove_storage_markers.rs:+3:16: +3:17 @@ -76,10 +79,14 @@ - StorageDead(_7); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6 - StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6 _5 = const (); // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6 - goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6 + goto -> bb2; // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6 } - bb3: { + bb5: { + unreachable; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 + } + + bb6: { _0 = const (); // scope 2 at $DIR/remove_storage_markers.rs:+2:5: +4:6 - StorageDead(_9); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6 - StorageDead(_7); // scope 2 at $DIR/remove_storage_markers.rs:+4:5: +4:6 @@ -89,12 +96,5 @@ - StorageDead(_1); // scope 0 at $DIR/remove_storage_markers.rs:+5:1: +5:2 return; // scope 0 at $DIR/remove_storage_markers.rs:+5:2: +5:2 } - - bb4: { -- StorageDead(_14); // scope 5 at $SRC_DIR/core/src/iter/range.rs:LL:COL -- StorageDead(_8); // scope 2 at $DIR/remove_storage_markers.rs:+2:18: +2:19 - _10 = discriminant(_7); // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - switchInt(move _10) -> [0_isize: bb3, otherwise: bb2]; // scope 2 at $DIR/remove_storage_markers.rs:+2:14: +2:19 - } } diff --git a/src/test/mir-opt/remove_storage_markers.rs b/src/test/mir-opt/remove_storage_markers.rs index c144d3ff795..f00b826911c 100644 --- a/src/test/mir-opt/remove_storage_markers.rs +++ b/src/test/mir-opt/remove_storage_markers.rs @@ -1,3 +1,5 @@ +// unit-test: RemoveStorageMarkers + // Checks that storage markers are removed at opt-level=0. // // compile-flags: -C opt-level=0 -Coverflow-checks=off diff --git a/src/test/mir-opt/remove_zsts_dont_touch_unions.rs b/src/test/mir-opt/remove_zsts_dont_touch_unions.rs index 7a6f86b8085..8b9de9b4d65 100644 --- a/src/test/mir-opt/remove_zsts_dont_touch_unions.rs +++ b/src/test/mir-opt/remove_zsts_dont_touch_unions.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmir-opt-level=3 +// unit-test: RemoveZsts // Ensure RemoveZsts doesn't remove ZST assignments to union fields, // which causes problems in Miri. diff --git a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir index 451d0fe4c02..05554174ae2 100644 --- a/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.array_casts.SimplifyCfg-elaborate-drops.after.mir @@ -80,7 +80,7 @@ fn array_casts() -> () { _7 = _2; // scope 3 at $DIR/retag.rs:+3:15: +3:16 _6 = ptr::mut_ptr::<impl *mut usize>::add(move _7, const 1_usize) -> bb1; // scope 3 at $DIR/retag.rs:+3:15: +3:23 // mir::Constant - // + span: $DIR/retag.rs:60:17: 60:20 + // + span: $DIR/retag.rs:61:17: 61:20 // + literal: Const { ty: unsafe fn(*mut usize, usize) -> *mut usize {ptr::mut_ptr::<impl *mut usize>::add}, val: Value(<ZST>) } } @@ -111,7 +111,7 @@ fn array_casts() -> () { _17 = _9; // scope 6 at $DIR/retag.rs:+7:26: +7:27 _16 = ptr::const_ptr::<impl *const usize>::add(move _17, const 1_usize) -> bb2; // scope 6 at $DIR/retag.rs:+7:26: +7:34 // mir::Constant - // + span: $DIR/retag.rs:64:28: 64:31 + // + span: $DIR/retag.rs:65:28: 65:31 // + literal: Const { ty: unsafe fn(*const usize, usize) -> *const usize {ptr::const_ptr::<impl *const usize>::add}, val: Value(<ZST>) } } diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir index ae6b5cfe21e..8802f3b2958 100644 --- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir @@ -73,7 +73,7 @@ fn main() -> () { Retag([2phase] _6); // scope 1 at $DIR/retag.rs:+3:29: +3:35 _3 = Test::foo(move _4, move _6) -> [return: bb1, unwind: bb8]; // scope 1 at $DIR/retag.rs:+3:17: +3:36 // mir::Constant - // + span: $DIR/retag.rs:32:25: 32:28 + // + span: $DIR/retag.rs:33:25: 33:28 // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x mut i32) -> &'x mut i32 {Test::foo}, val: Value(<ZST>) } } @@ -149,7 +149,7 @@ fn main() -> () { StorageLive(_23); // scope 7 at $DIR/retag.rs:+18:21: +18:23 _28 = const main::promoted[0]; // scope 7 at $DIR/retag.rs:+18:21: +18:23 // mir::Constant - // + span: $DIR/retag.rs:47:21: 47:23 + // + span: $DIR/retag.rs:48:21: 48:23 // + literal: Const { ty: &i32, val: Unevaluated(main, [], Some(promoted[0])) } Retag(_28); // scope 7 at $DIR/retag.rs:+18:21: +18:23 _23 = &(*_28); // scope 7 at $DIR/retag.rs:+18:21: +18:23 @@ -158,7 +158,7 @@ fn main() -> () { Retag(_22); // scope 7 at $DIR/retag.rs:+18:21: +18:23 _19 = Test::foo_shr(move _20, move _22) -> [return: bb4, unwind: bb7]; // scope 7 at $DIR/retag.rs:+18:5: +18:24 // mir::Constant - // + span: $DIR/retag.rs:47:13: 47:20 + // + span: $DIR/retag.rs:48:13: 48:20 // + literal: Const { ty: for<'r, 'x> fn(&'r Test, &'x i32) -> &'x i32 {Test::foo_shr}, val: Value(<ZST>) } } @@ -182,7 +182,7 @@ fn main() -> () { StorageLive(_27); // scope 8 at $DIR/retag.rs:+23:5: +23:18 _27 = array_casts() -> bb6; // scope 8 at $DIR/retag.rs:+23:5: +23:18 // mir::Constant - // + span: $DIR/retag.rs:52:5: 52:16 + // + span: $DIR/retag.rs:53:5: 53:16 // + literal: Const { ty: fn() {array_casts}, val: Value(<ZST>) } } diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs index 13568b822d4..86deb0e7ccd 100644 --- a/src/test/mir-opt/retag.rs +++ b/src/test/mir-opt/retag.rs @@ -1,3 +1,4 @@ +// unit-test: AddRetag // ignore-wasm32-bare compiled with panic=abort by default // ignore-tidy-linelength // compile-flags: -Z mir-emit-retag -Z mir-opt-level=0 -Z span_free_formats diff --git a/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir index e395fdb274f..25d400f0c9f 100644 --- a/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir @@ -1,6 +1,6 @@ -// MIR for `<impl at $DIR/retag.rs:11:1: 11:10>::foo` after SimplifyCfg-elaborate-drops +// MIR for `<impl at $DIR/retag.rs:12:1: 12:10>::foo` after SimplifyCfg-elaborate-drops -fn <impl at $DIR/retag.rs:11:1: 11:10>::foo(_1: &Test, _2: &mut i32) -> &mut i32 { +fn <impl at $DIR/retag.rs:12:1: 12:10>::foo(_1: &Test, _2: &mut i32) -> &mut i32 { debug self => _1; // in scope 0 at $DIR/retag.rs:+0:16: +0:21 debug x => _2; // in scope 0 at $DIR/retag.rs:+0:23: +0:24 let mut _0: &mut i32; // return place in scope 0 at $DIR/retag.rs:+0:42: +0:53 diff --git a/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir index e609166dec8..84ad8afc357 100644 --- a/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir @@ -1,6 +1,6 @@ -// MIR for `<impl at $DIR/retag.rs:11:1: 11:10>::foo_shr` after SimplifyCfg-elaborate-drops +// MIR for `<impl at $DIR/retag.rs:12:1: 12:10>::foo_shr` after SimplifyCfg-elaborate-drops -fn <impl at $DIR/retag.rs:11:1: 11:10>::foo_shr(_1: &Test, _2: &i32) -> &i32 { +fn <impl at $DIR/retag.rs:12:1: 12:10>::foo_shr(_1: &Test, _2: &i32) -> &i32 { debug self => _1; // in scope 0 at $DIR/retag.rs:+0:20: +0:25 debug x => _2; // in scope 0 at $DIR/retag.rs:+0:27: +0:28 let mut _0: &i32; // return place in scope 0 at $DIR/retag.rs:+0:42: +0:49 diff --git a/src/test/mir-opt/simplify-locals-removes-unused-consts.rs b/src/test/mir-opt/simplify-locals-removes-unused-consts.rs index 17999454472..39b7911d4ae 100644 --- a/src/test/mir-opt/simplify-locals-removes-unused-consts.rs +++ b/src/test/mir-opt/simplify-locals-removes-unused-consts.rs @@ -1,3 +1,4 @@ +// unit-test: SimplifyLocals // compile-flags: -C overflow-checks=no fn use_zst(_: ((), ())) {} diff --git a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff index da2f6fc440a..b41527ba02d 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff +++ b/src/test/mir-opt/simplify_locals_removes_unused_consts.main.SimplifyLocals.diff @@ -16,29 +16,53 @@ - let mut _11: Temp; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28 + let _1: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22 + let mut _2: ((), ()); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 -+ let _3: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 ++ let mut _3: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16 ++ let mut _4: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20 ++ let _5: (); // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 ++ let mut _6: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34 ++ let mut _7: u8; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30 ++ let mut _8: Temp; // in scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28 scope 1 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28 - StorageLive(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23 +- Deinit(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:21: +1:23 - StorageLive(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27 +- Deinit(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:25: +1:27 +- Deinit(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28 +- (_1.0: ()) = move _2; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28 +- (_1.1: ()) = move _3; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:20: +1:28 - StorageDead(_3); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:27: +1:28 - StorageDead(_2); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:27: +1:28 - StorageDead(_1); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+1:28: +1:29 - StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22 - StorageLive(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 - StorageLive(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16 +- Deinit(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16 - StorageLive(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20 +- Deinit(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20 +- Deinit(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 +- (_5.0: ()) = move _6; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 +- (_5.1: ()) = move _7; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 - StorageDead(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21 - StorageDead(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21 - _4 = use_zst(move _5) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22 + StorageLive(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22 + StorageLive(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 ++ StorageLive(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16 ++ Deinit(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:14: +2:16 ++ StorageLive(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20 ++ Deinit(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:18: +2:20 ++ Deinit(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 ++ (_2.0: ()) = move _3; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 ++ (_2.1: ()) = move _4; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:13: +2:21 ++ StorageDead(_4); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21 ++ StorageDead(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:20: +2:21 + _1 = use_zst(move _2) -> bb1; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:5: +2:22 // mir::Constant - // + span: $DIR/simplify-locals-removes-unused-consts.rs:14:5: 14:12 + // + span: $DIR/simplify-locals-removes-unused-consts.rs:15:5: 15:12 // + literal: Const { ty: fn(((), ())) {use_zst}, val: Value(<ZST>) } } @@ -49,22 +73,36 @@ - StorageLive(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34 - StorageLive(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30 - StorageLive(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28 +- Deinit(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28 +- (_11.0: u8) = const 40_u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28 +- _10 = (_11.0: u8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30 +- _9 = Add(move _10, const 2_u8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34 - StorageDead(_10); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:33: +4:34 -- _8 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 +- _8 = use_u8(move _9) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 + StorageDead(_2); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:21: +2:22 + StorageDead(_1); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+2:22: +2:23 -+ StorageLive(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 -+ _3 = use_u8(const 42_u8) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 ++ StorageLive(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 ++ StorageLive(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34 ++ StorageLive(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30 ++ StorageLive(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28 ++ Deinit(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28 ++ (_8.0: u8) = const 40_u8; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:28 ++ _7 = (_8.0: u8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:30 ++ _6 = Add(move _7, const 2_u8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:12: +4:34 ++ StorageDead(_7); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:33: +4:34 ++ _5 = use_u8(move _6) -> bb2; // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:5: +4:35 // mir::Constant - // + span: $DIR/simplify-locals-removes-unused-consts.rs:16:5: 16:11 + // + span: $DIR/simplify-locals-removes-unused-consts.rs:17:5: 17:11 // + literal: Const { ty: fn(u8) {use_u8}, val: Value(<ZST>) } } bb2: { - StorageDead(_9); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:34: +4:35 - StorageDead(_11); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36 -- StorageDead(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36 -+ StorageDead(_3); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36 ++ StorageDead(_6); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:34: +4:35 + StorageDead(_8); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36 ++ StorageDead(_5); // scope 1 at $DIR/simplify-locals-removes-unused-consts.rs:+4:35: +4:36 + _0 = const (); // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+0:11: +5:2 return; // scope 0 at $DIR/simplify-locals-removes-unused-consts.rs:+5:2: +5:2 } } diff --git a/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs b/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs index 2f740dc4fac..a2c7a31b7c3 100644 --- a/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs +++ b/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs @@ -1,6 +1,5 @@ // run-pass -#![feature(backtrace)] #[derive(Clone, Copy)] struct Foo { array: [u64; 10240], diff --git a/src/test/run-make/coverage-llvmir/filecheck.testprog.txt b/src/test/run-make/coverage-llvmir/filecheck.testprog.txt index 7a5f2192277..c943261d799 100644 --- a/src/test/run-make/coverage-llvmir/filecheck.testprog.txt +++ b/src/test/run-make/coverage-llvmir/filecheck.testprog.txt @@ -9,7 +9,7 @@ CHECK-SAME: section "[[INSTR_PROF_COVFUN]]"[[COMDAT_IF_SUPPORTED]], align 8 CHECK: @__llvm_coverage_mapping = private constant CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8 -WINDOWS: @__llvm_profile_runtime = external global i32 +WINDOWS: @__llvm_profile_runtime = external{{.*}}global i32 CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = {{private|internal}} global CHECK-SAME: section "[[INSTR_PROF_CNTS]]"{{.*}}, align 8 diff --git a/src/test/rustdoc-gui/label-next-to-symbol.goml b/src/test/rustdoc-gui/label-next-to-symbol.goml index ca3994a08b2..f9081189a86 100644 --- a/src/test/rustdoc-gui/label-next-to-symbol.goml +++ b/src/test/rustdoc-gui/label-next-to-symbol.goml @@ -7,14 +7,14 @@ size: (1080, 600) assert: (".stab.deprecated") assert: (".stab.portability") -// make sure that deprecated and portability are different colours +// make sure that deprecated and portability have the right colors assert-css: ( ".item-table .item-left .stab.deprecated", - { "background-color": "rgb(255, 196, 196)" }, + { "background-color": "rgb(255, 245, 214)" }, ) assert-css: ( ".item-table .item-left .stab.portability", - { "background-color": "rgb(243, 223, 255)" }, + { "background-color": "rgb(255, 245, 214)" }, ) // table like view @@ -51,7 +51,7 @@ assert-css: (".item-right.docblock-short", { "padding-left": "32px" }) compare-elements-position-near: ( "//*[@class='item-left module-item']//a[text()='replaced_function']", ".item-left .stab.deprecated", - {"y": 1}, + {"y": 2}, ) compare-elements-position: ( ".item-left .stab.deprecated", diff --git a/src/test/rustdoc-gui/pocket-menu.goml b/src/test/rustdoc-gui/pocket-menu.goml index 54f3790a765..782526e29f4 100644 --- a/src/test/rustdoc-gui/pocket-menu.goml +++ b/src/test/rustdoc-gui/pocket-menu.goml @@ -71,7 +71,7 @@ reload: click: "#help-button" assert-css: ( "#help-button .popover", - {"display": "block", "border-color": "rgb(221, 221, 221)"}, + {"display": "block", "border-color": "rgb(224, 224, 224)"}, ) compare-elements-css: ("#help-button .popover", "#help-button .top", ["border-color"]) compare-elements-css: ("#help-button .popover", "#help-button .bottom", ["border-color"]) diff --git a/src/test/rustdoc-gui/search-filter.goml b/src/test/rustdoc-gui/search-filter.goml index d645e237061..b12eddfd12a 100644 --- a/src/test/rustdoc-gui/search-filter.goml +++ b/src/test/rustdoc-gui/search-filter.goml @@ -40,7 +40,7 @@ press-key: "ArrowUp" press-key: "Enter" // Waiting for the search results to appear... wait-for: "#titles" -assert-property: ("#crate-search", {"value": "All crates"}) +assert-property: ("#crate-search", {"value": "all crates"}) // Checking that the URL parameter is taken into account for crate filtering. goto: file://|DOC_PATH|/test_docs/index.html?search=test&filter-crate=lib2 @@ -48,8 +48,8 @@ wait-for: "#crate-search" assert-property: ("#crate-search", {"value": "lib2"}) assert-false: "#results .externcrate" -// Checking that the text for the "title" is correct (the "All" comes from the "<select>"). -assert-text: ("#search-settings", "Results for test in All", STARTS_WITH) +// Checking that the text for the "title" is correct (the "all crates" comes from the "<select>"). +assert-text: (".search-results-title", "Results in all crates", STARTS_WITH) // Checking the display of the crate filter. // We start with the light theme. @@ -69,15 +69,15 @@ click: "#settings-menu" wait-for: "#settings" click: "#theme-dark" wait-for-css: ("#crate-search", { - "border": "1px solid rgb(240, 240, 240)", - "color": "rgb(17, 17, 17)", - "background-color": "rgb(240, 240, 240)", + "border": "1px solid rgb(210, 210, 210)", + "color": "rgb(221, 221, 221)", + "background-color": "rgb(53, 53, 53)", }) // And finally we check the ayu theme. click: "#theme-ayu" wait-for-css: ("#crate-search", { - "border": "1px solid rgb(66, 76, 87)", - "color": "rgb(197, 197, 197)", - "background-color": "rgb(20, 25, 32)", + "border": "1px solid rgb(92, 103, 115)", + "color": "rgb(255, 255, 255)", + "background-color": "rgb(15, 20, 25)", }) diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml index 8464ba7c23c..db4907924fa 100644 --- a/src/test/rustdoc-gui/search-result-display.goml +++ b/src/test/rustdoc-gui/search-result-display.goml @@ -4,7 +4,7 @@ size: (900, 1000) write: (".search-input", "test") // To be SURE that the search will be run. press-key: 'Enter' -wait-for: "#search-settings" +wait-for: "#crate-search" // The width is returned by "getComputedStyle" which returns the exact number instead of the // CSS rule which is "50%"... assert-css: (".search-results div.desc", {"width": "295px"}) @@ -17,13 +17,9 @@ assert-css: (".search-results div.desc", {"width": "570px"}) // To do so we need to update the length of one of its `<option>`. size: (900, 900) -// First we check the current width and position. -assert-css: ("#crate-search", {"width": "218px"}) -compare-elements-position-near: ( - "#crate-search", - "#search-settings .search-results-title", - {"y": 5}, -) +// First we check the current width, height and position. +assert-css: ("#crate-search", {"width": "223px"}) +assert-css: (".search-results-title", {"height": "44px", "width": "336px"}) // Then we update the text of one of the `<option>`. text: ( @@ -31,12 +27,8 @@ text: ( "sdjfaksdjfaksjdbfkadsbfkjsadbfkdsbkfbsadkjfbkdsabfkadsfkjdsafa", ) -// Then we compare again. -assert-css: ("#crate-search", {"width": "640px"}) -compare-elements-position-near-false: ( - "#crate-search", - "#search-settings .search-results-title", - {"y": 5}, -) -// And we check that the `<select>` isn't bigger than its container. +// Then we compare again to confirm the height didn't change. +assert-css: ("#crate-search", {"width": "527px"}) +assert-css: (".search-results-title", {"height": "44px", "width": "640px"}) +// And we check that the `<select>` isn't bigger than its container (".search-results-title"). assert-css: ("#search", {"width": "640px"}) diff --git a/src/test/rustdoc-gui/sidebar-mobile-scroll.goml b/src/test/rustdoc-gui/sidebar-mobile-scroll.goml new file mode 100644 index 00000000000..b3bcea25338 --- /dev/null +++ b/src/test/rustdoc-gui/sidebar-mobile-scroll.goml @@ -0,0 +1,31 @@ +// This test ensures that the mobile sidebar preserves scroll position. +goto: file://|DOC_PATH|/test_docs/struct.Foo.html +// Switching to "mobile view" by reducing the width to 600px. +size: (600, 600) +assert-css: (".sidebar", {"display": "block", "left": "-1000px"}) + +// Scroll down. +scroll-to: "//h2[@id='blanket-implementations']" +assert-window-property: {"pageYOffset": "702"} + +// Open the sidebar menu. +click: ".sidebar-menu-toggle" +wait-for-css: (".sidebar", {"left": "0px"}) + +// We are no longer "scrolled". It's important that the user can't +// scroll the body at all, but these test scripts are run only in Chrome, +// and we need to use a more complicated solution to this problem because +// of Mobile Safari... +assert-window-property: {"pageYOffset": "0"} + +// Close the sidebar menu. Make sure the scroll position gets restored. +click: ".sidebar-menu-toggle" +wait-for-css: (".sidebar", {"left": "-1000px"}) +assert-window-property: {"pageYOffset": "702"} + +// Now test that scrollability returns when the browser window is just resized. +click: ".sidebar-menu-toggle" +wait-for-css: (".sidebar", {"left": "0px"}) +assert-window-property: {"pageYOffset": "0"} +size: (900, 900) +assert-window-property: {"pageYOffset": "702"} diff --git a/src/test/rustdoc-gui/sidebar-source-code-display.goml b/src/test/rustdoc-gui/sidebar-source-code-display.goml index fa322574fde..e4662a10ed5 100644 --- a/src/test/rustdoc-gui/sidebar-source-code-display.goml +++ b/src/test/rustdoc-gui/sidebar-source-code-display.goml @@ -233,6 +233,17 @@ wait-for-css: (".sidebar", {"width": "0px"}) // The "scrollTop" property should be the same. assert-window-property: {"pageYOffset": "2519"} +// We now check that the scroll position is restored if the window is resized. +size: (500, 700) +click: "#sidebar-toggle" +wait-for-css: ("#source-sidebar", {"visibility": "visible"}) +assert-window-property: {"pageYOffset": "0"} +size: (900, 900) +assert-window-property: {"pageYOffset": "2519"} +size: (500, 700) +click: "#sidebar-toggle" +wait-for-css: ("#source-sidebar", {"visibility": "hidden"}) + // We now check that opening the sidebar and clicking a link will close it. // The behavior here on mobile is different than the behavior on desktop, // but common sense dictates that if you have a list of files that fills the entire screen, and diff --git a/src/test/rustdoc-json/primitive.rs b/src/test/rustdoc-json/primitive.rs index b84c2f7c6ac..8d1141b5864 100644 --- a/src/test/rustdoc-json/primitive.rs +++ b/src/test/rustdoc-json/primitive.rs @@ -7,8 +7,14 @@ mod usize {} // @set local_crate_id = primitive.json "$.index[*][?(@.name=='primitive')].crate_id" -// @has - "$.index[*][?(@.name=='log10')]" -// @!is - "$.index[*][?(@.name=='log10')].crate_id" $local_crate_id +// @has - "$.index[*][?(@.name=='ilog10')]" +// @!is - "$.index[*][?(@.name=='ilog10')].crate_id" $local_crate_id // @has - "$.index[*][?(@.name=='checked_add')]" // @!is - "$.index[*][?(@.name=='checked_add')]" $local_crate_id // @!has - "$.index[*][?(@.name=='is_ascii_uppercase')]" + +// @is - "$.index[*][?(@.kind=='import' && @.inner.name=='my_i32')].inner.id" null +pub use i32 as my_i32; + +// @is - "$.index[*][?(@.kind=='import' && @.inner.name=='u32')].inner.id" null +pub use u32; diff --git a/src/test/rustdoc-ui/z-help.stdout b/src/test/rustdoc-ui/z-help.stdout index 6dc41231559..236469ce979 100644 --- a/src/test/rustdoc-ui/z-help.stdout +++ b/src/test/rustdoc-ui/z-help.stdout @@ -38,6 +38,7 @@ -Z emit-stack-sizes=val -- emit a section containing stack size metadata (default: no) -Z emit-thin-lto=val -- emit the bc module with thin LTO info (default: yes) -Z export-executable-symbols=val -- export symbols from executables, as if they were dynamic libraries + -Z extra-const-ub-checks=val -- turns on more checks to detect const UB, which can be slow (default: no) -Z fewer-names=val -- reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) (default: no) -Z force-unstable-if-unmarked=val -- force all crates to be `rustc_private` unstable (default: no) -Z fuel=val -- set the optimization fuel quota for a crate diff --git a/src/test/rustdoc/empty-impl-block-private-with-doc.rs b/src/test/rustdoc/empty-impl-block-private-with-doc.rs new file mode 100644 index 00000000000..43971996163 --- /dev/null +++ b/src/test/rustdoc/empty-impl-block-private-with-doc.rs @@ -0,0 +1,44 @@ +// compile-flags: --document-private-items + +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] +#![crate_name = "foo"] + +// @has 'foo/struct.Foo.html' +pub struct Foo; + +// There are 3 impl blocks with public item and one that should not be displayed +// by default because it only contains private items (but not in this case because +// we used `--document-private-items`). +// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 4 + +// Impl block only containing private items should not be displayed unless the +// `--document-private-items` flag is used. +/// Private +impl Foo { + const BAR: u32 = 0; + type FOO = i32; + fn hello() {} +} + +// But if any element of the impl block is public, it should be displayed. +/// Not private +impl Foo { + pub const BAR: u32 = 0; + type FOO = i32; + fn hello() {} +} + +/// Not private +impl Foo { + const BAR: u32 = 0; + pub type FOO = i32; + fn hello() {} +} + +/// Not private +impl Foo { + const BAR: u32 = 0; + type FOO = i32; + pub fn hello() {} +} diff --git a/src/test/rustdoc/empty-impl-block-private.rs b/src/test/rustdoc/empty-impl-block-private.rs new file mode 100644 index 00000000000..5caf020658c --- /dev/null +++ b/src/test/rustdoc/empty-impl-block-private.rs @@ -0,0 +1,40 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] +#![crate_name = "foo"] + +// @has 'foo/struct.Foo.html' +pub struct Foo; + +// There are 3 impl blocks with public item and one that should not be displayed +// because it only contains private items. +// @count - '//*[@class="impl has-srclink"]' 'impl Foo' 3 + +// Impl block only containing private items should not be displayed. +/// Private +impl Foo { + const BAR: u32 = 0; + type FOO = i32; + fn hello() {} +} + +// But if any element of the impl block is public, it should be displayed. +/// Not private +impl Foo { + pub const BAR: u32 = 0; + type FOO = i32; + fn hello() {} +} + +/// Not private +impl Foo { + const BAR: u32 = 0; + pub type FOO = i32; + fn hello() {} +} + +/// Not private +impl Foo { + const BAR: u32 = 0; + type FOO = i32; + pub fn hello() {} +} diff --git a/src/test/rustdoc/intra-doc/assoc-reexport-super.rs b/src/test/rustdoc/intra-doc/assoc-reexport-super.rs new file mode 100644 index 00000000000..a7bc1c6a29f --- /dev/null +++ b/src/test/rustdoc/intra-doc/assoc-reexport-super.rs @@ -0,0 +1,20 @@ +// Regression test for #93205 + +#![crate_name = "foo"] + +mod generated { + pub struct MyNewType; + impl MyNewType { + pub const FOO: Self = Self; + } +} + +pub use generated::MyNewType; + +mod prelude { + impl super::MyNewType { + /// An alias for [`Self::FOO`]. + // @has 'foo/struct.MyNewType.html' '//a[@href="struct.MyNewType.html#associatedconstant.FOO"]' 'Self::FOO' + pub const FOO2: Self = Self::FOO; + } +} diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index a679b7b4e19..0d9c9350efc 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -74,10 +74,10 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P<Expr>)) { 2 => { let seg = PathSegment::from_ident(Ident::from_str("x")); iter_exprs(depth - 1, &mut |e| { - g(ExprKind::MethodCall(seg.clone(), vec![e, make_x()], DUMMY_SP)) + g(ExprKind::MethodCall(seg.clone(), e, vec![make_x()], DUMMY_SP)) }); iter_exprs(depth - 1, &mut |e| { - g(ExprKind::MethodCall(seg.clone(), vec![make_x(), e], DUMMY_SP)) + g(ExprKind::MethodCall(seg.clone(), make_x(), vec![e], DUMMY_SP)) }); } 3..=8 => { diff --git a/src/test/ui/associated-types/issue-22560.stderr b/src/test/ui/associated-types/issue-22560.stderr index 700923c1b3f..2b88cf0b441 100644 --- a/src/test/ui/associated-types/issue-22560.stderr +++ b/src/test/ui/associated-types/issue-22560.stderr @@ -1,25 +1,3 @@ -error[E0393]: the type parameter `Rhs` must be explicitly specified - --> $DIR/issue-22560.rs:9:23 - | -LL | trait Sub<Rhs=Self> { - | ------------------- type parameter `Rhs` must be specified for this -... -LL | type Test = dyn Add + Sub; - | ^^^ help: set the type parameter to the desired type: `Sub<Rhs>` - | - = note: because of the default `Self` reference, type parameters must be specified on object types - -error[E0393]: the type parameter `Rhs` must be explicitly specified - --> $DIR/issue-22560.rs:9:17 - | -LL | trait Add<Rhs=Self> { - | ------------------- type parameter `Rhs` must be specified for this -... -LL | type Test = dyn Add + Sub; - | ^^^ help: set the type parameter to the desired type: `Add<Rhs>` - | - = note: because of the default `Self` reference, type parameters must be specified on object types - error[E0225]: only auto traits can be used as additional traits in a trait object --> $DIR/issue-22560.rs:9:23 | @@ -28,7 +6,7 @@ LL | type Test = dyn Add + Sub; | | | first non-auto trait | - = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add<[type error]> + Sub<[type error]> {}` + = help: consider creating a new trait with all of these as supertraits and using that trait here instead: `trait NewTrait: Add + Sub {}` = note: auto-traits like `Send` and `Sync` are traits that have special properties; for more information on them, visit <https://doc.rust-lang.org/reference/special-types-and-traits.html#auto-traits> error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified @@ -50,6 +28,28 @@ help: specify the associated types LL | type Test = dyn Add<Output = Type> + Sub<Output = Type>; | ~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~ +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/issue-22560.rs:9:17 + | +LL | trait Add<Rhs=Self> { + | ------------------- type parameter `Rhs` must be specified for this +... +LL | type Test = dyn Add + Sub; + | ^^^ help: set the type parameter to the desired type: `Add<Rhs>` + | + = note: because of the default `Self` reference, type parameters must be specified on object types + +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/issue-22560.rs:9:23 + | +LL | trait Sub<Rhs=Self> { + | ------------------- type parameter `Rhs` must be specified for this +... +LL | type Test = dyn Add + Sub; + | ^^^ help: set the type parameter to the desired type: `Sub<Rhs>` + | + = note: because of the default `Self` reference, type parameters must be specified on object types + error: aborting due to 4 previous errors Some errors have detailed explanations: E0191, E0225, E0393. diff --git a/src/test/ui/associated-types/issue-59324.rs b/src/test/ui/associated-types/issue-59324.rs index 162f9e00edd..9e68e9e7751 100644 --- a/src/test/ui/associated-types/issue-59324.rs +++ b/src/test/ui/associated-types/issue-59324.rs @@ -15,9 +15,9 @@ pub trait ThriftService<Bug: NotFoo>: { fn get_service( //~^ ERROR the trait bound `Bug: Foo` is not satisfied + //~| ERROR the trait bound `Bug: Foo` is not satisfied &self, ) -> Self::AssocType; - //~^ the trait bound `Bug: Foo` is not satisfied } fn with_factory<H>(factory: dyn ThriftService<()>) {} diff --git a/src/test/ui/associated-types/issue-59324.stderr b/src/test/ui/associated-types/issue-59324.stderr index a84b599b52b..dd5ec7175b5 100644 --- a/src/test/ui/associated-types/issue-59324.stderr +++ b/src/test/ui/associated-types/issue-59324.stderr @@ -20,7 +20,7 @@ LL | | LL | | LL | | Service<AssocType = <Bug as Foo>::OnlyFoo> ... | -LL | | +LL | | ) -> Self::AssocType; LL | | } | |_^ the trait `Foo` is not implemented for `Bug` | @@ -34,6 +34,7 @@ error[E0277]: the trait bound `Bug: Foo` is not satisfied | LL | / fn get_service( LL | | +LL | | LL | | &self, LL | | ) -> Self::AssocType; | |_________________________^ the trait `Foo` is not implemented for `Bug` @@ -50,10 +51,10 @@ LL | fn with_factory<H>(factory: dyn ThriftService<()>) {} | ^^^^^^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `()` error[E0277]: the trait bound `Bug: Foo` is not satisfied - --> $DIR/issue-59324.rs:19:10 + --> $DIR/issue-59324.rs:16:8 | -LL | ) -> Self::AssocType; - | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug` +LL | fn get_service( + | ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug` | help: consider further restricting this bound | diff --git a/src/test/ui/backtrace-apple-no-dsymutil.rs b/src/test/ui/backtrace-apple-no-dsymutil.rs index d32ad11a122..3844ebcfd30 100644 --- a/src/test/ui/backtrace-apple-no-dsymutil.rs +++ b/src/test/ui/backtrace-apple-no-dsymutil.rs @@ -4,8 +4,6 @@ // compile-flags:-g -Csplit-debuginfo=unpacked // only-macos -#![feature(backtrace)] - use std::process::Command; use std::str; diff --git a/src/test/ui/cfg/cfg-method-receiver.rs b/src/test/ui/cfg/cfg-method-receiver.rs new file mode 100644 index 00000000000..78a072f503f --- /dev/null +++ b/src/test/ui/cfg/cfg-method-receiver.rs @@ -0,0 +1,12 @@ +macro_rules! cbor_map { + ($key:expr) => { + $key.signum(); + //~^ ERROR can't call method `signum` on ambiguous numeric type `{integer}` [E0689] + }; +} + +fn main() { + cbor_map! { #[cfg(test)] 4}; + //~^ ERROR attributes on expressions are experimental + //~| ERROR removing an expression is not supported in this position +} diff --git a/src/test/ui/cfg/cfg-method-receiver.stderr b/src/test/ui/cfg/cfg-method-receiver.stderr new file mode 100644 index 00000000000..517fc8168e7 --- /dev/null +++ b/src/test/ui/cfg/cfg-method-receiver.stderr @@ -0,0 +1,34 @@ +error[E0658]: attributes on expressions are experimental + --> $DIR/cfg-method-receiver.rs:9:17 + | +LL | cbor_map! { #[cfg(test)] 4}; + | ^^^^^^^^^^^^ + | + = note: see issue #15701 <https://github.com/rust-lang/rust/issues/15701> for more information + = help: add `#![feature(stmt_expr_attributes)]` to the crate attributes to enable + +error: removing an expression is not supported in this position + --> $DIR/cfg-method-receiver.rs:9:17 + | +LL | cbor_map! { #[cfg(test)] 4}; + | ^^^^^^^^^^^^ + +error[E0689]: can't call method `signum` on ambiguous numeric type `{integer}` + --> $DIR/cfg-method-receiver.rs:3:14 + | +LL | $key.signum(); + | ^^^^^^ +... +LL | cbor_map! { #[cfg(test)] 4}; + | --------------------------- in this macro invocation + | + = note: this error originates in the macro `cbor_map` (in Nightly builds, run with -Z macro-backtrace for more info) +help: you must specify a concrete type for this numeric value, like `i32` + | +LL | cbor_map! { #[cfg(test)] 4_i32}; + | ~~~~~ + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0658, E0689. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-100217.rs b/src/test/ui/const-generics/generic_const_exprs/issue-100217.rs new file mode 100644 index 00000000000..acdc348a385 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-100217.rs @@ -0,0 +1,42 @@ +// build-pass + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +trait TraitOne { + const MY_NUM: usize; + type MyErr: std::fmt::Debug; + + fn do_one_stuff(arr: [u8; Self::MY_NUM]) -> Result<(), Self::MyErr>; +} + +trait TraitTwo { + fn do_two_stuff(); +} + +impl<O: TraitOne> TraitTwo for O +where + [(); Self::MY_NUM]:, +{ + fn do_two_stuff() { + O::do_one_stuff([5; Self::MY_NUM]).unwrap() + } +} + +struct Blargotron; + +#[derive(Debug)] +struct ErrTy<const N: usize>([(); N]); + +impl TraitOne for Blargotron { + const MY_NUM: usize = 3; + type MyErr = ErrTy<{ Self::MY_NUM }>; + + fn do_one_stuff(_arr: [u8; Self::MY_NUM]) -> Result<(), Self::MyErr> { + Ok(()) + } +} + +fn main() { + Blargotron::do_two_stuff(); +} diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-73298.rs b/src/test/ui/const-generics/generic_const_exprs/issue-73298.rs new file mode 100644 index 00000000000..3c59e1b790a --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-73298.rs @@ -0,0 +1,23 @@ +// build-pass + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +use std::convert::AsMut; +use std::default::Default; + +trait Foo: Sized { + type Baz: Default + AsMut<[u8]>; + fn bar() { + Self::Baz::default().as_mut(); + } +} + +impl Foo for () { + type Baz = [u8; 1 * 1]; + //type Baz = [u8; 1]; +} + +fn main() { + <() as Foo>::bar(); +} diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-82268.rs b/src/test/ui/const-generics/generic_const_exprs/issue-82268.rs new file mode 100644 index 00000000000..d08fc5beb75 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-82268.rs @@ -0,0 +1,73 @@ +// build-pass + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +trait Collate<Op> { + type Pass; + type Fail; + + fn collate(self) -> (Self::Pass, Self::Fail); +} + +impl<Op> Collate<Op> for () { + type Pass = (); + type Fail = (); + + fn collate(self) -> ((), ()) { + ((), ()) + } +} + +trait CollateStep<X, Prev> { + type Pass; + type Fail; + fn collate_step(x: X, prev: Prev) -> (Self::Pass, Self::Fail); +} + +impl<X, P, F> CollateStep<X, (P, F)> for () { + type Pass = (X, P); + type Fail = F; + + fn collate_step(x: X, (p, f): (P, F)) -> ((X, P), F) { + ((x, p), f) + } +} + +struct CollateOpImpl<const MASK: u32>; +trait CollateOpStep { + type NextOp; + type Apply; +} + +impl<const MASK: u32> CollateOpStep for CollateOpImpl<MASK> +where + CollateOpImpl<{ MASK >> 1 }>: Sized, +{ + type NextOp = CollateOpImpl<{ MASK >> 1 }>; + type Apply = (); +} + +impl<H, T, Op: CollateOpStep> Collate<Op> for (H, T) +where + T: Collate<Op::NextOp>, + Op::Apply: CollateStep<H, (T::Pass, T::Fail)>, +{ + type Pass = <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::Pass; + type Fail = <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::Fail; + + fn collate(self) -> (Self::Pass, Self::Fail) { + <Op::Apply as CollateStep<H, (T::Pass, T::Fail)>>::collate_step(self.0, self.1.collate()) + } +} + +fn collate<X, const MASK: u32>(x: X) -> (X::Pass, X::Fail) +where + X: Collate<CollateOpImpl<MASK>>, +{ + x.collate() +} + +fn main() { + dbg!(collate::<_, 5>(("Hello", (42, ('!', ()))))); +} diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-83972.rs b/src/test/ui/const-generics/generic_const_exprs/issue-83972.rs new file mode 100644 index 00000000000..0063719b852 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-83972.rs @@ -0,0 +1,38 @@ +// build-pass + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +pub trait Foo { + fn foo(&self); +} + +pub struct FooImpl<const N: usize>; +impl<const N: usize> Foo for FooImpl<N> { + fn foo(&self) {} +} + +pub trait Bar: 'static { + type Foo: Foo; + fn get() -> &'static Self::Foo; +} + +struct BarImpl; +impl Bar for BarImpl { + type Foo = FooImpl< + { + { 4 } + }, + >; + fn get() -> &'static Self::Foo { + &FooImpl + } +} + +pub fn boom<B: Bar>() { + B::get().foo(); +} + +fn main() { + boom::<BarImpl>(); +} diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-84669.rs b/src/test/ui/const-generics/generic_const_exprs/issue-84669.rs new file mode 100644 index 00000000000..3933ff20a49 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-84669.rs @@ -0,0 +1,30 @@ +// build-pass + +#![feature(generic_const_exprs)] +#![allow(incomplete_features)] + +trait Foo { + type Output; + + fn foo() -> Self::Output; +} + +impl Foo for [u8; 3] { + type Output = [u8; 1 + 2]; + + fn foo() -> [u8; 3] { + [1u8; 3] + } +} + +fn bug<const N: usize>() +where + [u8; N]: Foo, + <[u8; N] as Foo>::Output: AsRef<[u8]>, +{ + <[u8; N]>::foo().as_ref(); +} + +fn main() { + bug::<3>(); +} diff --git a/src/test/ui/const-generics/generic_const_exprs/issue-86710.rs b/src/test/ui/const-generics/generic_const_exprs/issue-86710.rs new file mode 100644 index 00000000000..bdd8a21b3b9 --- /dev/null +++ b/src/test/ui/const-generics/generic_const_exprs/issue-86710.rs @@ -0,0 +1,73 @@ +// build-pass + +#![allow(incomplete_features)] +#![feature(generic_const_exprs)] + +use std::marker::PhantomData; + +fn main() { + let x = FooImpl::<BarImpl<1>> { phantom: PhantomData }; + let _ = x.foo::<BarImpl<1>>(); +} + +trait Foo<T> +where + T: Bar, +{ + fn foo<U>(&self) + where + T: Operation<U>, + <T as Operation<U>>::Output: Bar; +} + +struct FooImpl<T> +where + T: Bar, +{ + phantom: PhantomData<T>, +} + +impl<T> Foo<T> for FooImpl<T> +where + T: Bar, +{ + fn foo<U>(&self) + where + T: Operation<U>, + <T as Operation<U>>::Output: Bar, + { + <<T as Operation<U>>::Output as Bar>::error_occurs_here(); + } +} + +trait Bar { + fn error_occurs_here(); +} + +struct BarImpl<const N: usize>; + +impl<const N: usize> Bar for BarImpl<N> { + fn error_occurs_here() {} +} + +trait Operation<Rhs> { + type Output; +} + +//// Part-A: This causes error. +impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> +where + BarImpl<{ N + M }>: Sized, +{ + type Output = BarImpl<{ N + M }>; +} + +//// Part-B: This doesn't cause error. +// impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> { +// type Output = BarImpl<M>; +// } + +//// Part-C: This also doesn't cause error. +// impl<const M: usize, const N: usize> Operation<BarImpl<M>> for BarImpl<N> { +// type Output = BarImpl<{ M }>; +// } diff --git a/src/test/ui/const-generics/issues/issue-100313.rs b/src/test/ui/const-generics/issues/issue-100313.rs new file mode 100644 index 00000000000..4e9d3626aa8 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-100313.rs @@ -0,0 +1,21 @@ +#![allow(incomplete_features)] +#![feature(const_mut_refs)] +#![feature(adt_const_params)] + +struct T<const B: &'static bool>; + +impl <const B: &'static bool> T<B> { + const fn set_false(&self) { + unsafe { + *(B as *const bool as *mut bool) = false; + //~^ ERROR evaluation of constant value failed [E0080] + } + } +} + +const _: () = { + let x = T::<{&true}>; + x.set_false(); +}; + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-100313.stderr b/src/test/ui/const-generics/issues/issue-100313.stderr new file mode 100644 index 00000000000..f3ce357c2bb --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-100313.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/issue-100313.rs:10:13 + | +LL | *(B as *const bool as *mut bool) = false; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | writing to alloc7 which is read-only + | inside `T::<&true>::set_false` at $DIR/issue-100313.rs:10:13 +... +LL | x.set_false(); + | ------------- inside `_` at $DIR/issue-100313.rs:18:5 + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const_in_pattern/incomplete-slice.rs b/src/test/ui/consts/const_in_pattern/incomplete-slice.rs new file mode 100644 index 00000000000..e1ccda71d40 --- /dev/null +++ b/src/test/ui/consts/const_in_pattern/incomplete-slice.rs @@ -0,0 +1,15 @@ +#[derive(PartialEq)] +enum E { + A, +} + +const E_SL: &[E] = &[E::A]; + +fn main() { + match &[][..] { + //~^ ERROR non-exhaustive patterns: `&_` not covered [E0004] + E_SL => {} + //~^ WARN to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]` + //~| WARN this was previously accepted by the compiler but is being phased out + } +} diff --git a/src/test/ui/consts/const_in_pattern/incomplete-slice.stderr b/src/test/ui/consts/const_in_pattern/incomplete-slice.stderr new file mode 100644 index 00000000000..0ff70837138 --- /dev/null +++ b/src/test/ui/consts/const_in_pattern/incomplete-slice.stderr @@ -0,0 +1,26 @@ +warning: to use a constant of type `E` in a pattern, `E` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/incomplete-slice.rs:11:9 + | +LL | E_SL => {} + | ^^^^ + | + = note: `#[warn(indirect_structural_match)]` 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 #62411 <https://github.com/rust-lang/rust/issues/62411> + +error[E0004]: non-exhaustive patterns: `&_` not covered + --> $DIR/incomplete-slice.rs:9:11 + | +LL | match &[][..] { + | ^^^^^^^ pattern `&_` not covered + | + = note: the matched value is of type `&[E]` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ E_SL => {} +LL + &_ => todo!() + | + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs b/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs new file mode 100644 index 00000000000..97c9e150519 --- /dev/null +++ b/src/test/ui/consts/extra-const-ub/detect-extra-ub.rs @@ -0,0 +1,45 @@ +// revisions: no_flag with_flag +// [no_flag] check-pass +// [with_flag] compile-flags: -Zextra-const-ub-checks +#![feature(const_ptr_read)] + +use std::mem::transmute; + +const INVALID_BOOL: () = unsafe { + let _x: bool = transmute(3u8); + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value +}; + +const INVALID_PTR_IN_INT: () = unsafe { + let _x: usize = transmute(&3u8); + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value +}; + +const INVALID_SLICE_TO_USIZE_TRANSMUTE: () = unsafe { + let x: &[u8] = &[0; 32]; + let _x: (usize, usize) = transmute(x); + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value +}; + +const UNALIGNED_PTR: () = unsafe { + let _x: &u32 = transmute(&[0u8; 4]); + //[with_flag]~^ ERROR: evaluation of constant value failed + //[with_flag]~| invalid value +}; + +const UNALIGNED_READ: () = { + INNER; //[with_flag]~ERROR any use of this value will cause an error + //[with_flag]~| previously accepted + // There is an error here but its span is in the standard library so we cannot match it... + // so we have this in a *nested* const, such that the *outer* const fails to use it. + const INNER: () = unsafe { + let x = &[0u8; 4]; + let ptr = x.as_ptr().cast::<u32>(); + ptr.read(); + }; +}; + +fn main() {} diff --git a/src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr b/src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr new file mode 100644 index 00000000000..1706db7ac43 --- /dev/null +++ b/src/test/ui/consts/extra-const-ub/detect-extra-ub.with_flag.stderr @@ -0,0 +1,71 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:9:20 + | +LL | let _x: bool = transmute(3u8); + | ^^^^^^^^^^^^^^ constructing invalid value: encountered 0x03, but expected a boolean + +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:15:21 + | +LL | let _x: usize = transmute(&3u8); + | ^^^^^^^^^^^^^^^ constructing invalid value: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:22:30 + | +LL | let _x: (usize, usize) = transmute(x); + | ^^^^^^^^^^^^ constructing invalid value at .0: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + +error[E0080]: evaluation of constant value failed + --> $DIR/detect-extra-ub.rs:28:20 + | +LL | let _x: &u32 = transmute(&[0u8; 4]); + | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 4 byte alignment but found 1) + +error[E0080]: evaluation of constant value failed + --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | +LL | copy_nonoverlapping(src, tmp.as_mut_ptr(), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | accessing memory with alignment 1, but alignment 4 is required + | inside `std::ptr::read::<u32>` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + | + ::: $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | +LL | unsafe { read(self) } + | ---------- inside `ptr::const_ptr::<impl *const u32>::read` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | + ::: $DIR/detect-extra-ub.rs:41:9 + | +LL | ptr.read(); + | ---------- inside `INNER` at $DIR/detect-extra-ub.rs:41:9 + +error: any use of this value will cause an error + --> $DIR/detect-extra-ub.rs:34:5 + | +LL | const UNALIGNED_READ: () = { + | ------------------------ +LL | INNER; + | ^^^^^ 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 6 previous errors + +For more information about this error, try `rustc --explain E0080`. +Future incompatibility report: Future breakage diagnostic: +error: any use of this value will cause an error + --> $DIR/detect-extra-ub.rs:34:5 + | +LL | const UNALIGNED_READ: () = { + | ------------------------ +LL | INNER; + | ^^^^^ 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> + diff --git a/src/test/ui/copy-a-resource.stderr b/src/test/ui/copy-a-resource.stderr index 128087f1e37..b92449c6e0a 100644 --- a/src/test/ui/copy-a-resource.stderr +++ b/src/test/ui/copy-a-resource.stderr @@ -10,6 +10,10 @@ LL | let _y = x.clone(); = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `Clone` +help: one of the expressions' fields has a method of the same name + | +LL | let _y = x.i.clone(); + | ++ error: aborting due to previous error diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs index b2edc1a1f66..6175b7df110 100644 --- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs +++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.rs @@ -3,7 +3,6 @@ trait Foo<X = Box<dyn Foo>> { //~^ ERROR cycle detected - //~| ERROR cycle detected } fn main() { } diff --git a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr index d4976a0f9c9..9d715f49471 100644 --- a/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr +++ b/src/test/ui/cycle-trait/cycle-trait-default-type-trait.stderr @@ -10,30 +10,11 @@ note: cycle used when collecting item types in top-level module | LL | / trait Foo<X = Box<dyn Foo>> { LL | | -LL | | -LL | | } -LL | | -LL | | fn main() { } - | |_____________^ - -error[E0391]: cycle detected when computing type of `Foo::X` - --> $DIR/cycle-trait-default-type-trait.rs:4:23 - | -LL | trait Foo<X = Box<dyn Foo>> { - | ^^^ - | - = note: ...which immediately requires computing type of `Foo::X` again -note: cycle used when collecting item types in top-level module - --> $DIR/cycle-trait-default-type-trait.rs:4:1 - | -LL | / trait Foo<X = Box<dyn Foo>> { -LL | | -LL | | LL | | } LL | | LL | | fn main() { } | |_____________^ -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0391`. diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs index 5a92bcd37b6..5d924555625 100644 --- a/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.rs @@ -1,4 +1,4 @@ -// check-pass +// check-fail trait Trait { type Type; @@ -17,6 +17,7 @@ where fn g<'a, 'b>() { f::<'a, 'b>(()); + //~^ ERROR lifetime may not live long enough } fn main() {} diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr new file mode 100644 index 00000000000..0c3df04eabc --- /dev/null +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-2.stderr @@ -0,0 +1,17 @@ +error: lifetime may not live long enough + --> $DIR/implied-bounds-unnorm-associated-type-2.rs:19:5 + | +LL | fn g<'a, 'b>() { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | f::<'a, 'b>(()); + | ^^^^^^^^^^^^^^^ requires that `'b` must outlive `'a` + | + = help: consider adding the following bound: `'b: 'a` + = note: requirement occurs because of a function pointer to `f` + = note: the function `f` 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/fn/implied-bounds-unnorm-associated-type-3.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs index dc25ac08613..888f74cf6b3 100644 --- a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.rs @@ -1,6 +1,4 @@ -// check-fail -// See issue #91899. If we treat unnormalized args as WF, `Self` can also be a -// source of unsoundness. +// check-pass pub trait Yokeable<'a>: 'static { type Output: 'a; @@ -17,7 +15,6 @@ pub trait ZeroCopyFrom<C: ?Sized>: for<'a> Yokeable<'a> { impl<T> ZeroCopyFrom<[T]> for &'static [T] { fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] { - //~^ the parameter cart } } diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr deleted file mode 100644 index 95cf4fb168f..00000000000 --- a/src/test/ui/fn/implied-bounds-unnorm-associated-type-3.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error[E0310]: the parameter type `T` may not live long enough - --> $DIR/implied-bounds-unnorm-associated-type-3.rs:19:5 - | -LL | fn zero_copy_from<'b>(cart: &'b [T]) -> &'b [T] { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the type `[T]` will meet its required lifetime bounds - | -help: consider adding an explicit lifetime bound... - | -LL | impl<T: 'static> ZeroCopyFrom<[T]> for &'static [T] { - | +++++++++ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0310`. diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs new file mode 100644 index 00000000000..12859252c87 --- /dev/null +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.rs @@ -0,0 +1,24 @@ +// A regression test for #98543 + +trait Trait { + type Type; +} + +impl<T> Trait for T { + type Type = (); +} + +fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str +where + &'a &'b (): Trait, // <- adding this bound is the change from #91068 +{ + s +} + +fn main() { + let x = String::from("Hello World!"); + let y = f(&x, ()); + drop(x); + //~^ ERROR cannot move out of `x` because it is borrowed + println!("{}", y); +} diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr new file mode 100644 index 00000000000..fcbaa91d19f --- /dev/null +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-4.stderr @@ -0,0 +1,14 @@ +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/implied-bounds-unnorm-associated-type-4.rs:21:10 + | +LL | let y = f(&x, ()); + | -- borrow of `x` occurs here +LL | drop(x); + | ^ move out of `x` occurs here +LL | +LL | println!("{}", y); + | - borrow later used here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs new file mode 100644 index 00000000000..2a9a6a8cc6c --- /dev/null +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.rs @@ -0,0 +1,23 @@ +trait Trait<'a>: 'a { + type Type; +} + +// if the `T: 'a` bound gets implied we would probably get ub here again +impl<'a, T> Trait<'a> for T { + //~^ ERROR the parameter type `T` may not live long enough + type Type = (); +} + +fn f<'a, 'b>(s: &'b str, _: <&'b () as Trait<'a>>::Type) -> &'a str +where + &'b (): Trait<'a>, +{ + s +} + +fn main() { + let x = String::from("Hello World!"); + let y = f(&x, ()); + drop(x); + println!("{}", y); +} diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr new file mode 100644 index 00000000000..458756a3dcd --- /dev/null +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type-5.stderr @@ -0,0 +1,19 @@ +error[E0309]: the parameter type `T` may not live long enough + --> $DIR/implied-bounds-unnorm-associated-type-5.rs:6:13 + | +LL | impl<'a, T> Trait<'a> for T { + | ^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds... + | +note: ...that is required by this bound + --> $DIR/implied-bounds-unnorm-associated-type-5.rs:1:18 + | +LL | trait Trait<'a>: 'a { + | ^^ +help: consider adding an explicit lifetime bound... + | +LL | impl<'a, T: 'a> Trait<'a> for T { + | ++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0309`. diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs b/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs index 04b6f4dd84e..d58d25036c5 100644 --- a/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type.rs @@ -1,6 +1,6 @@ // check-fail -// See issue #91068. Types in the substs of an associated type can't be implied -// to be WF, since they don't actually have to be constructed. +// See issue #91068. We check that the unnormalized associated types in +// function signatures are implied trait Trait { type Type; @@ -12,12 +12,12 @@ impl<T> Trait for T { fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str { s - //~^ ERROR lifetime may not live long enough } fn main() { let x = String::from("Hello World!"); let y = f(&x, ()); drop(x); + //~^ ERROR cannot move out of `x` because it is borrowed println!("{}", y); } diff --git a/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr b/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr index 8096f08385c..e35f46e4439 100644 --- a/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr +++ b/src/test/ui/fn/implied-bounds-unnorm-associated-type.stderr @@ -1,14 +1,14 @@ -error: lifetime may not live long enough - --> $DIR/implied-bounds-unnorm-associated-type.rs:14:5 +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/implied-bounds-unnorm-associated-type.rs:20:10 | -LL | fn f<'a, 'b>(s: &'b str, _: <&'a &'b () as Trait>::Type) -> &'a str { - | -- -- lifetime `'b` defined here - | | - | lifetime `'a` defined here -LL | s - | ^ 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` +LL | let y = f(&x, ()); + | -- borrow of `x` occurs here +LL | drop(x); + | ^ move out of `x` occurs here +LL | +LL | println!("{}", y); + | - borrow later used here error: aborting due to previous error +For more information about this error, try `rustc --explain E0505`. diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr b/src/test/ui/generic-associated-types/bugs/issue-87748.stderr deleted file mode 100644 index ac197dfe6ff..00000000000 --- a/src/test/ui/generic-associated-types/bugs/issue-87748.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error[E0478]: lifetime bound not satisfied - --> $DIR/issue-87748.rs:18:5 - | -LL | fn do_sth(_: u32) {} - | ^^^^^^^^^^^^^^^^^ - | -note: lifetime parameter instantiated with the anonymous lifetime as defined here - --> $DIR/issue-87748.rs:18:5 - | -LL | fn do_sth(_: u32) {} - | ^^^^^^^^^^^^^^^^^ -note: but lifetime parameter must outlive the anonymous lifetime as defined here - --> $DIR/issue-87748.rs:18:5 - | -LL | fn do_sth(_: u32) {} - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0478`. diff --git a/src/test/ui/generic-associated-types/bugs/issue-87748.rs b/src/test/ui/generic-associated-types/issue-87748.rs index a3d00ee03b1..1a1ab9bf8a4 100644 --- a/src/test/ui/generic-associated-types/bugs/issue-87748.rs +++ b/src/test/ui/generic-associated-types/issue-87748.rs @@ -1,13 +1,14 @@ -// check-fail -// known-bug: #87748 +// Checks that we properly add implied bounds from unnormalized projections in +// inputs when typechecking functions. -// This should pass, but unnormalized input args aren't treated as implied. +// check-pass #![feature(generic_associated_types)] trait MyTrait { type Assoc<'a, 'b> where 'b: 'a; fn do_sth(arg: Self::Assoc<'_, '_>); + fn do_sth2(arg: Self::Assoc<'_, '_>) {} } struct Foo; @@ -16,8 +17,7 @@ impl MyTrait for Foo { type Assoc<'a, 'b> = u32 where 'b: 'a; fn do_sth(_: u32) {} - // fn do_sth(_: Self::Assoc<'static, 'static>) {} - // fn do_sth(_: Self::Assoc<'_, '_>) {} + fn do_sth2(_: Self::Assoc<'static, 'static>) {} } fn main() {} diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs index 172bf218c0d..de9348f5397 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs @@ -7,7 +7,6 @@ trait SomeTrait<'a> { fn give_me_ice<T>() { callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>(); //~^ ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277] - //~| ERROR the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied [E0277] } fn callee<T: Fn<(&'static (),)>>() { diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr index ecca4b999e7..6a948a116e0 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr @@ -9,17 +9,6 @@ help: consider restricting type parameter `T` LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() { | +++++++++++++++++++++++ -error[E0277]: the trait bound `for<'r> T: SomeTrait<'r>` is not satisfied - --> $DIR/issue-85455.rs:8:14 - | -LL | callee::<fn(&()) -> <T as SomeTrait<'_>>::Associated>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `for<'r> SomeTrait<'r>` is not implemented for `T` - | -help: consider restricting type parameter `T` - | -LL | fn give_me_ice<T: for<'r> SomeTrait<'r>>() { - | +++++++++++++++++++++++ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/hrtb/issue-30786.stderr b/src/test/ui/hrtb/issue-30786.stderr index bc7b5e914e1..ffe3d7b81f5 100644 --- a/src/test/ui/hrtb/issue-30786.stderr +++ b/src/test/ui/hrtb/issue-30786.stderr @@ -18,10 +18,6 @@ note: the following trait bounds were not satisfied: | LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here -help: one of the expressions' fields has a method of the same name - | -LL | let filter = map.stream.filterx(|x: &_| true); - | +++++++ error[E0599]: the method `countx` exists for struct `Filter<Map<Repeat, for<'r> fn(&'r u64) -> &'r u64 {identity::<u64>}>, [closure@$DIR/issue-30786.rs:129:30: 129:37]>`, but its trait bounds were not satisfied --> $DIR/issue-30786.rs:130:24 @@ -43,10 +39,6 @@ note: the following trait bounds were not satisfied: | LL | impl<T> StreamExt for T where for<'a> &'a mut T: Stream {} | --------- - ^^^^^^ unsatisfied trait bound introduced here -help: one of the expressions' fields has a method of the same name - | -LL | let count = filter.stream.countx(); - | +++++++ error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/issue-100187.rs b/src/test/ui/impl-trait/issue-100187.rs new file mode 100644 index 00000000000..fc541c69629 --- /dev/null +++ b/src/test/ui/impl-trait/issue-100187.rs @@ -0,0 +1,12 @@ +// check-pass + +trait Trait<T> { + type Ty; +} +impl Trait<&u8> for () { + type Ty = (); +} + +fn test<'a, 'b>() -> impl Trait<&'a u8, Ty = impl Sized + 'b> {} + +fn main() {} diff --git a/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.rs b/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.rs new file mode 100644 index 00000000000..33b746c5edf --- /dev/null +++ b/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.rs @@ -0,0 +1,27 @@ +// Test for a less than ideal interaction of implied bounds and normalization. +trait Tr { + type Ty; +} + +impl<T: 'static> Tr for T { + type Ty = &'static T; +} + +// `<&'a u8 as Tr>::Ty` should cause an error because `&'a u8: Tr` doesn't hold for +// all possible 'a. However, we consider normalized types for implied bounds. +// +// We normalize this projection to `&'static &'a u8` and add a nested `&'a u8: 'static` +// bound. This bound is then proven using the implied bounds for `&'static &'a u8` which +// we only get by normalizing in the first place. +fn test<'a>(x: &'a u8, _wf: <&'a u8 as Tr>::Ty) -> &'static u8 { x } + +fn main() { + // This works as we have 'static references due to promotion. + let _: &'static u8 = test(&3, &&3); + // This causes an error because the projection requires 'a to be 'static. + // It would be unsound if this compiled. + let x: u8 = 3; + let _: &'static u8 = test(&x, &&3); + //~^ ERROR `x` does not live long enough + +} diff --git a/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr b/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr new file mode 100644 index 00000000000..d0249e74f39 --- /dev/null +++ b/src/test/ui/implied-bounds/assoc-ty-wf-used-to-get-assoc-ty.stderr @@ -0,0 +1,15 @@ +error[E0597]: `x` does not live long enough + --> $DIR/assoc-ty-wf-used-to-get-assoc-ty.rs:24:31 + | +LL | let _: &'static u8 = test(&x, &&3); + | -----^^------ + | | | + | | borrowed value does not live long enough + | argument requires that `x` is borrowed for `'static` +... +LL | } + | - `x` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/issues/issue-21950.stderr b/src/test/ui/issues/issue-21950.stderr index 4909398bb84..731615a6bd8 100644 --- a/src/test/ui/issues/issue-21950.stderr +++ b/src/test/ui/issues/issue-21950.stderr @@ -1,3 +1,12 @@ +error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified + --> $DIR/issue-21950.rs:10:25 + | +LL | type Output; + | ----------- `Output` defined here +... +LL | let x = &10 as &dyn Add; + | ^^^ help: specify the associated type: `Add<Output = Type>` + error[E0393]: the type parameter `Rhs` must be explicitly specified --> $DIR/issue-21950.rs:10:25 | @@ -9,15 +18,6 @@ LL | let x = &10 as &dyn Add; | = note: because of the default `Self` reference, type parameters must be specified on object types -error[E0191]: the value of the associated type `Output` (from trait `Add`) must be specified - --> $DIR/issue-21950.rs:10:25 - | -LL | type Output; - | ----------- `Output` defined here -... -LL | let x = &10 as &dyn Add; - | ^^^ help: specify the associated type: `Add<Output = Type>` - error: aborting due to 2 previous errors Some errors have detailed explanations: E0191, E0393. diff --git a/src/test/ui/issues/issue-2823.stderr b/src/test/ui/issues/issue-2823.stderr index b5a2b2f55a6..208b340d064 100644 --- a/src/test/ui/issues/issue-2823.stderr +++ b/src/test/ui/issues/issue-2823.stderr @@ -10,6 +10,10 @@ LL | let _d = c.clone(); = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `Clone` +help: one of the expressions' fields has a method of the same name + | +LL | let _d = c.x.clone(); + | ++ error: aborting due to previous error diff --git a/src/test/ui/json-multiple.stderr b/src/test/ui/json-multiple.stderr deleted file mode 100644 index 7ed345113cb..00000000000 --- a/src/test/ui/json-multiple.stderr +++ /dev/null @@ -1 +0,0 @@ -{"artifact":"$TEST_BUILD_DIR/json-multiple/libjson_multiple.rlib","emit":"link"} diff --git a/src/test/ui/json-options.stderr b/src/test/ui/json-options.stderr deleted file mode 100644 index 24977731d17..00000000000 --- a/src/test/ui/json-options.stderr +++ /dev/null @@ -1 +0,0 @@ -{"artifact":"$TEST_BUILD_DIR/json-options/libjson_options.rlib","emit":"link"} diff --git a/src/test/ui/json-and-color.rs b/src/test/ui/json/json-and-color.rs index 6f8326fe247..6f8326fe247 100644 --- a/src/test/ui/json-and-color.rs +++ b/src/test/ui/json/json-and-color.rs diff --git a/src/test/ui/json-and-color.stderr b/src/test/ui/json/json-and-color.stderr index 1cda6af090d..1cda6af090d 100644 --- a/src/test/ui/json-and-color.stderr +++ b/src/test/ui/json/json-and-color.stderr diff --git a/src/test/ui/json-and-error-format.rs b/src/test/ui/json/json-and-error-format.rs index 6e2d73c76b7..6e2d73c76b7 100644 --- a/src/test/ui/json-and-error-format.rs +++ b/src/test/ui/json/json-and-error-format.rs diff --git a/src/test/ui/json-and-error-format.stderr b/src/test/ui/json/json-and-error-format.stderr index 80e0221376e..80e0221376e 100644 --- a/src/test/ui/json-and-error-format.stderr +++ b/src/test/ui/json/json-and-error-format.stderr diff --git a/src/test/ui/json-bom-plus-crlf-multifile-aux.rs b/src/test/ui/json/json-bom-plus-crlf-multifile-aux.rs index 991ea1d85d2..991ea1d85d2 100644 --- a/src/test/ui/json-bom-plus-crlf-multifile-aux.rs +++ b/src/test/ui/json/json-bom-plus-crlf-multifile-aux.rs diff --git a/src/test/ui/json-bom-plus-crlf-multifile.rs b/src/test/ui/json/json-bom-plus-crlf-multifile.rs index 9290e010403..9290e010403 100644 --- a/src/test/ui/json-bom-plus-crlf-multifile.rs +++ b/src/test/ui/json/json-bom-plus-crlf-multifile.rs diff --git a/src/test/ui/json-bom-plus-crlf-multifile.stderr b/src/test/ui/json/json-bom-plus-crlf-multifile.stderr index 02f3bc687cb..02f3bc687cb 100644 --- a/src/test/ui/json-bom-plus-crlf-multifile.stderr +++ b/src/test/ui/json/json-bom-plus-crlf-multifile.stderr diff --git a/src/test/ui/json-bom-plus-crlf.rs b/src/test/ui/json/json-bom-plus-crlf.rs index be5b7dd2a86..be5b7dd2a86 100644 --- a/src/test/ui/json-bom-plus-crlf.rs +++ b/src/test/ui/json/json-bom-plus-crlf.rs diff --git a/src/test/ui/json-bom-plus-crlf.stderr b/src/test/ui/json/json-bom-plus-crlf.stderr index df6bd7286a6..df6bd7286a6 100644 --- a/src/test/ui/json-bom-plus-crlf.stderr +++ b/src/test/ui/json/json-bom-plus-crlf.stderr diff --git a/src/test/ui/json-invalid.rs b/src/test/ui/json/json-invalid.rs index 54d0dd1849a..54d0dd1849a 100644 --- a/src/test/ui/json-invalid.rs +++ b/src/test/ui/json/json-invalid.rs diff --git a/src/test/ui/json-invalid.stderr b/src/test/ui/json/json-invalid.stderr index 18bc76ab7eb..18bc76ab7eb 100644 --- a/src/test/ui/json-invalid.stderr +++ b/src/test/ui/json/json-invalid.stderr diff --git a/src/test/ui/json-multiple.polonius.stderr b/src/test/ui/json/json-multiple.polonius.stderr index 0e4d442f299..0e4d442f299 100644 --- a/src/test/ui/json-multiple.polonius.stderr +++ b/src/test/ui/json/json-multiple.polonius.stderr diff --git a/src/test/ui/json-multiple.rs b/src/test/ui/json/json-multiple.rs index fb126339dc2..fb126339dc2 100644 --- a/src/test/ui/json-multiple.rs +++ b/src/test/ui/json/json-multiple.rs diff --git a/src/test/ui/json/json-multiple.stderr b/src/test/ui/json/json-multiple.stderr new file mode 100644 index 00000000000..55ccfd5fa70 --- /dev/null +++ b/src/test/ui/json/json-multiple.stderr @@ -0,0 +1 @@ +{"artifact":"$TEST_BUILD_DIR/json/json-multiple/libjson_multiple.rlib","emit":"link"} diff --git a/src/test/ui/json-options.polonius.stderr b/src/test/ui/json/json-options.polonius.stderr index e21f6f85d16..e21f6f85d16 100644 --- a/src/test/ui/json-options.polonius.stderr +++ b/src/test/ui/json/json-options.polonius.stderr diff --git a/src/test/ui/json-options.rs b/src/test/ui/json/json-options.rs index 8b6ba131eb0..8b6ba131eb0 100644 --- a/src/test/ui/json-options.rs +++ b/src/test/ui/json/json-options.rs diff --git a/src/test/ui/json/json-options.stderr b/src/test/ui/json/json-options.stderr new file mode 100644 index 00000000000..645a26f5ad4 --- /dev/null +++ b/src/test/ui/json/json-options.stderr @@ -0,0 +1 @@ +{"artifact":"$TEST_BUILD_DIR/json/json-options/libjson_options.rlib","emit":"link"} diff --git a/src/test/ui/json-short.rs b/src/test/ui/json/json-short.rs index 7414a55869c..7414a55869c 100644 --- a/src/test/ui/json-short.rs +++ b/src/test/ui/json/json-short.rs diff --git a/src/test/ui/json-short.stderr b/src/test/ui/json/json-short.stderr index 3bd85b083d0..3bd85b083d0 100644 --- a/src/test/ui/json-short.stderr +++ b/src/test/ui/json/json-short.stderr diff --git a/src/test/ui/lint/unused_parens_multibyte_recovery.rs b/src/test/ui/lint/unused_parens_multibyte_recovery.rs new file mode 100644 index 00000000000..8fcfae22a3d --- /dev/null +++ b/src/test/ui/lint/unused_parens_multibyte_recovery.rs @@ -0,0 +1,11 @@ +// ignore-tidy-trailing-newlines +// +// error-pattern: this file contains an unclosed delimiter +// error-pattern: this file contains an unclosed delimiter +// error-pattern: this file contains an unclosed delimiter +// error-pattern: format argument must be a string literal +// +// Verify that unused parens lint does not try to create a span +// which points in the middle of a multibyte character. + +fn f(){(print!(á \ No newline at end of file diff --git a/src/test/ui/lint/unused_parens_multibyte_recovery.stderr b/src/test/ui/lint/unused_parens_multibyte_recovery.stderr new file mode 100644 index 00000000000..a0302b17e25 --- /dev/null +++ b/src/test/ui/lint/unused_parens_multibyte_recovery.stderr @@ -0,0 +1,43 @@ +error: this file contains an unclosed delimiter + --> $DIR/unused_parens_multibyte_recovery.rs:11:17 + | +LL | fn f(){(print!(á + | -- - ^ + | || | + | || unclosed delimiter + | |unclosed delimiter + | unclosed delimiter + +error: this file contains an unclosed delimiter + --> $DIR/unused_parens_multibyte_recovery.rs:11:17 + | +LL | fn f(){(print!(á + | -- - ^ + | || | + | || unclosed delimiter + | |unclosed delimiter + | unclosed delimiter + +error: this file contains an unclosed delimiter + --> $DIR/unused_parens_multibyte_recovery.rs:11:17 + | +LL | fn f(){(print!(á + | -- - ^ + | || | + | || unclosed delimiter + | |unclosed delimiter + | unclosed delimiter + +error: format argument must be a string literal + --> $DIR/unused_parens_multibyte_recovery.rs:11:16 + | +LL | fn f(){(print!(á + | ^ + | +help: you might be missing a string literal to format with + | +LL | fn f(){(print!("{}", á + | +++++ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/lowering/issue-96847.rs b/src/test/ui/lowering/issue-96847.rs new file mode 100644 index 00000000000..2aa34c8b335 --- /dev/null +++ b/src/test/ui/lowering/issue-96847.rs @@ -0,0 +1,14 @@ +// run-pass + +// Test that this doesn't abort during AST lowering. In #96847 it did abort +// because the attribute was being lowered twice. + +#![feature(stmt_expr_attributes)] +#![feature(lang_items)] + +fn main() { + for _ in [1,2,3] { + #![lang="foo"] + println!("foo"); + } +} diff --git a/src/test/ui/macros/stringify.rs b/src/test/ui/macros/stringify.rs index f246aa26a9d..8e71ed7c112 100644 --- a/src/test/ui/macros/stringify.rs +++ b/src/test/ui/macros/stringify.rs @@ -865,8 +865,9 @@ fn test_vis() { assert_eq!(stringify_vis!(pub(crate)), "pub(crate) "); assert_eq!(stringify_vis!(pub(self)), "pub(self) "); assert_eq!(stringify_vis!(pub(super)), "pub(super) "); - assert_eq!(stringify_vis!(pub(in self)), "pub(self) "); - assert_eq!(stringify_vis!(pub(in super)), "pub(super) "); + assert_eq!(stringify_vis!(pub(in crate)), "pub(in crate) "); + assert_eq!(stringify_vis!(pub(in self)), "pub(in self) "); + assert_eq!(stringify_vis!(pub(in super)), "pub(in super) "); assert_eq!(stringify_vis!(pub(in path::to)), "pub(in path::to) "); assert_eq!(stringify_vis!(pub(in ::path::to)), "pub(in ::path::to) "); assert_eq!(stringify_vis!(pub(in self::path::to)), "pub(in self::path::to) "); diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs index c4db6fc97dc..05e2ea047f6 100644 --- a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs +++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.rs @@ -30,4 +30,5 @@ fn main() { let _x = <fn(&())>::make_f(); //~^ ERROR implementation of `Y` is not general enough //~| ERROR implementation of `Y` is not general enough + //~| ERROR implementation of `Y` is not general enough } diff --git a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr index 51adfca3e79..8c47379886d 100644 --- a/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr +++ b/src/test/ui/nll/relate_tys/impl-fn-ignore-binder-via-bottom.stderr @@ -16,5 +16,14 @@ LL | let _x = <fn(&())>::make_f(); = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())` = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` -error: aborting due to 2 previous errors +error: implementation of `Y` is not general enough + --> $DIR/impl-fn-ignore-binder-via-bottom.rs:30:14 + | +LL | let _x = <fn(&())>::make_f(); + | ^^^^^^^^^^^^^^^^^^^ implementation of `Y` is not general enough + | + = note: `Y` would have to be implemented for the type `for<'r> fn(&'r ())` + = note: ...but `Y` is actually implemented for the type `fn(&'0 ())`, for some specific lifetime `'0` + +error: aborting due to 3 previous errors diff --git a/src/test/ui/noncopyable-class.stderr b/src/test/ui/noncopyable-class.stderr index 0c696163a26..15e22e946da 100644 --- a/src/test/ui/noncopyable-class.stderr +++ b/src/test/ui/noncopyable-class.stderr @@ -10,6 +10,14 @@ LL | let _y = x.clone(); = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `clone`, perhaps you need to implement it: candidate #1: `Clone` +help: one of the expressions' fields has a method of the same name + | +LL | let _y = x.i.clone(); + | ++ +help: one of the expressions' fields has a method of the same name + | +LL | let _y = x.j.x.clone(); + | ++++ error: aborting due to previous error diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs new file mode 100644 index 00000000000..7ebf3f6b0d8 --- /dev/null +++ b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.rs @@ -0,0 +1,8 @@ +fn foo() {} + +fn bar() -> [u8; 2] { + foo() + [1, 3) //~ ERROR expected one of `.`, `?`, `]`, or an operator, found `,` +} + +fn main() {} diff --git a/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr new file mode 100644 index 00000000000..d6e8db80329 --- /dev/null +++ b/src/test/ui/parser/do-not-suggest-suggest-semicolon-before-array.stderr @@ -0,0 +1,10 @@ +error: expected one of `.`, `?`, `]`, or an operator, found `,` + --> $DIR/do-not-suggest-suggest-semicolon-before-array.rs:5:5 + | +LL | [1, 3) + | ^ ^ help: `]` may belong here + | | + | unclosed delimiter + +error: aborting due to previous error + diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed b/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed new file mode 100644 index 00000000000..a06b58b2740 --- /dev/null +++ b/src/test/ui/parser/suggest-suggest-semicolon-before-array.fixed @@ -0,0 +1,11 @@ +// run-rustfix +#![allow(dead_code)] + +fn foo() {} + +fn bar() -> [u8; 2] { + foo(); + [1, 3] //~ ERROR expected `;`, found `[` +} + +fn main() {} diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs b/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs new file mode 100644 index 00000000000..f601ca2aef5 --- /dev/null +++ b/src/test/ui/parser/suggest-suggest-semicolon-before-array.rs @@ -0,0 +1,11 @@ +// run-rustfix +#![allow(dead_code)] + +fn foo() {} + +fn bar() -> [u8; 2] { + foo() + [1, 3] //~ ERROR expected `;`, found `[` +} + +fn main() {} diff --git a/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr b/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr new file mode 100644 index 00000000000..bf86b43554d --- /dev/null +++ b/src/test/ui/parser/suggest-suggest-semicolon-before-array.stderr @@ -0,0 +1,13 @@ +error: expected `;`, found `[` + --> $DIR/suggest-suggest-semicolon-before-array.rs:8:5 + | +LL | [1, 3] + | ^ + | +help: consider adding `;` here + | +LL | foo(); + | + + +error: aborting due to previous error + diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs index d9657bac776..5dce8180f59 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.rs @@ -1,5 +1,4 @@ // aux-build:enums.rs -// run-pass extern crate enums; @@ -7,11 +6,6 @@ use enums::FieldLessWithNonExhaustiveVariant; fn main() { let e = FieldLessWithNonExhaustiveVariant::default(); - // FIXME: https://github.com/rust-lang/rust/issues/91161 - // This `as` cast *should* be an error, since it would fail - // if the non-exhaustive variant got fields. But today it - // doesn't. The fix for that will update this test to - // show an error (and not be run-pass any more). - let d = e as u8; + let d = e as u8; //~ ERROR casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid [E0606] assert_eq!(d, 0); } diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr new file mode 100644 index 00000000000..a61dcf8399f --- /dev/null +++ b/src/test/ui/rfc-2008-non-exhaustive/enum-as-cast.stderr @@ -0,0 +1,11 @@ +error[E0606]: casting `FieldLessWithNonExhaustiveVariant` as `u8` is invalid + --> $DIR/enum-as-cast.rs:9:13 + | +LL | let d = e as u8; + | ^^^^^^^ + | + = note: cannot cast an enum with a non-exhaustive variant when it's defined in another crate + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0606`. diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs new file mode 100644 index 00000000000..99f317399d7 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.rs @@ -0,0 +1,18 @@ +#![feature(raw_dylib)] +//~^ WARN the feature `raw_dylib` is incomplete + +#[link(name = "foo")] +extern "C" { + #[link_ordinal(3)] + //~^ ERROR `#[link_ordinal]` is only supported if link kind is `raw-dylib` + fn foo(); +} + +#[link(name = "bar", kind = "static")] +extern "C" { + #[link_ordinal(3)] + //~^ ERROR `#[link_ordinal]` is only supported if link kind is `raw-dylib` + fn bar(); +} + +fn main() {} diff --git a/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr new file mode 100644 index 00000000000..f1eeb22da59 --- /dev/null +++ b/src/test/ui/rfc-2627-raw-dylib/link-ordinal-unsupported-link-kind.stderr @@ -0,0 +1,23 @@ +warning: the feature `raw_dylib` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/link-ordinal-unsupported-link-kind.rs:1:12 + | +LL | #![feature(raw_dylib)] + | ^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #58713 <https://github.com/rust-lang/rust/issues/58713> for more information + +error: `#[link_ordinal]` is only supported if link kind is `raw-dylib` + --> $DIR/link-ordinal-unsupported-link-kind.rs:6:5 + | +LL | #[link_ordinal(3)] + | ^^^^^^^^^^^^^^^^^^ + +error: `#[link_ordinal]` is only supported if link kind is `raw-dylib` + --> $DIR/link-ordinal-unsupported-link-kind.rs:13:5 + | +LL | #[link_ordinal(3)] + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/src/test/ui/stats/hir-stats.rs b/src/test/ui/stats/hir-stats.rs new file mode 100644 index 00000000000..a24b3ada57e --- /dev/null +++ b/src/test/ui/stats/hir-stats.rs @@ -0,0 +1,41 @@ +// check-pass +// compile-flags: -Zhir-stats +// only-x86_64 + +// The aim here is to include at least one of every different type of top-level +// AST/HIR node reported by `-Zhir-stats`. + +#![allow(dead_code)] + +use std::arch::asm; +use std::fmt::Debug; +use std::ffi::c_void; + +extern "C" { fn f(p: *mut c_void); } + +/// An enum. +enum E<'a, T: Copy> { A { t: T }, B(&'a u32) } + +trait Go { + type G: Debug; + fn go(self) -> u32; +} + +impl<'a, T: Copy> Go for E<'a, T> { + type G = bool; + fn go(self) -> u32 { + 99 + } +} + +fn f2<T>(t: T) where T: Debug {} + +fn main() { + let x = E::A { t: 3 }; + match x { + E::A { .. } => {} + _ => {} + } + + unsafe { asm!("mov rdi, 1"); } +} diff --git a/src/test/ui/stats/hir-stats.stderr b/src/test/ui/stats/hir-stats.stderr new file mode 100644 index 00000000000..f4874408c90 --- /dev/null +++ b/src/test/ui/stats/hir-stats.stderr @@ -0,0 +1,151 @@ + +PRE EXPANSION AST STATS + +Name Accumulated Size Count Item Size +---------------------------------------------------------------- +ExprField 48 ( 0.5%) 1 48 +GenericArgs 64 ( 0.7%) 1 64 +- AngleBracketed 64 ( 0.7%) 1 +Local 72 ( 0.8%) 1 72 +WherePredicate 72 ( 0.8%) 1 72 +- BoundPredicate 72 ( 0.8%) 1 +Crate 72 ( 0.8%) 1 72 +Arm 96 ( 1.0%) 2 48 +FieldDef 160 ( 1.7%) 2 80 +ForeignItem 160 ( 1.7%) 1 160 +- Fn 160 ( 1.7%) 1 +Stmt 160 ( 1.7%) 5 32 +- Local 32 ( 0.3%) 1 +- MacCall 32 ( 0.3%) 1 +- Expr 96 ( 1.0%) 3 +Param 160 ( 1.7%) 4 40 +FnDecl 200 ( 2.2%) 5 40 +Variant 240 ( 2.6%) 2 120 +Block 288 ( 3.1%) 6 48 +Attribute 304 ( 3.3%) 2 152 +- Normal 152 ( 1.7%) 1 +- DocComment 152 ( 1.7%) 1 +GenericBound 352 ( 3.8%) 4 88 +- Trait 352 ( 3.8%) 4 +GenericParam 520 ( 5.7%) 5 104 +AssocItem 640 ( 7.0%) 4 160 +- TyAlias 320 ( 3.5%) 2 +- Fn 320 ( 3.5%) 2 +PathSegment 720 ( 7.9%) 30 24 +Expr 832 ( 9.1%) 8 104 +- Path 104 ( 1.1%) 1 +- Match 104 ( 1.1%) 1 +- Struct 104 ( 1.1%) 1 +- Lit 208 ( 2.3%) 2 +- Block 312 ( 3.4%) 3 +Pat 840 ( 9.2%) 7 120 +- Struct 120 ( 1.3%) 1 +- Wild 120 ( 1.3%) 1 +- Ident 600 ( 6.6%) 5 +Ty 1_344 (14.7%) 14 96 +- Rptr 96 ( 1.0%) 1 +- Ptr 96 ( 1.0%) 1 +- ImplicitSelf 192 ( 2.1%) 2 +- Path 960 (10.5%) 10 +Item 1_800 (19.7%) 9 200 +- Trait 200 ( 2.2%) 1 +- Enum 200 ( 2.2%) 1 +- ForeignMod 200 ( 2.2%) 1 +- Impl 200 ( 2.2%) 1 +- Fn 400 ( 4.4%) 2 +- Use 600 ( 6.6%) 3 +---------------------------------------------------------------- +Total 9_144 + + +POST EXPANSION AST STATS + +Name Accumulated Size Count Item Size +---------------------------------------------------------------- +ExprField 48 ( 0.5%) 1 48 +GenericArgs 64 ( 0.6%) 1 64 +- AngleBracketed 64 ( 0.6%) 1 +Local 72 ( 0.7%) 1 72 +WherePredicate 72 ( 0.7%) 1 72 +- BoundPredicate 72 ( 0.7%) 1 +Crate 72 ( 0.7%) 1 72 +Arm 96 ( 0.9%) 2 48 +InlineAsm 120 ( 1.2%) 1 120 +FieldDef 160 ( 1.6%) 2 80 +ForeignItem 160 ( 1.6%) 1 160 +- Fn 160 ( 1.6%) 1 +Stmt 160 ( 1.6%) 5 32 +- Local 32 ( 0.3%) 1 +- Semi 32 ( 0.3%) 1 +- Expr 96 ( 0.9%) 3 +Param 160 ( 1.6%) 4 40 +FnDecl 200 ( 2.0%) 5 40 +Variant 240 ( 2.4%) 2 120 +Block 288 ( 2.8%) 6 48 +GenericBound 352 ( 3.5%) 4 88 +- Trait 352 ( 3.5%) 4 +GenericParam 520 ( 5.1%) 5 104 +Attribute 608 ( 6.0%) 4 152 +- DocComment 152 ( 1.5%) 1 +- Normal 456 ( 4.5%) 3 +AssocItem 640 ( 6.3%) 4 160 +- TyAlias 320 ( 3.2%) 2 +- Fn 320 ( 3.2%) 2 +PathSegment 792 ( 7.8%) 33 24 +Pat 840 ( 8.3%) 7 120 +- Struct 120 ( 1.2%) 1 +- Wild 120 ( 1.2%) 1 +- Ident 600 ( 5.9%) 5 +Expr 936 ( 9.2%) 9 104 +- Path 104 ( 1.0%) 1 +- Match 104 ( 1.0%) 1 +- Struct 104 ( 1.0%) 1 +- InlineAsm 104 ( 1.0%) 1 +- Lit 208 ( 2.1%) 2 +- Block 312 ( 3.1%) 3 +Ty 1_344 (13.2%) 14 96 +- Rptr 96 ( 0.9%) 1 +- Ptr 96 ( 0.9%) 1 +- ImplicitSelf 192 ( 1.9%) 2 +- Path 960 ( 9.5%) 10 +Item 2_200 (21.7%) 11 200 +- Trait 200 ( 2.0%) 1 +- Enum 200 ( 2.0%) 1 +- ExternCrate 200 ( 2.0%) 1 +- ForeignMod 200 ( 2.0%) 1 +- Impl 200 ( 2.0%) 1 +- Fn 400 ( 3.9%) 2 +- Use 800 ( 7.9%) 4 +---------------------------------------------------------------- +Total 10_144 + + +HIR STATS + +Name Accumulated Size Count Item Size +---------------------------------------------------------------- +Param 64 ( 0.7%) 2 32 +Local 64 ( 0.7%) 1 64 +ForeignItem 72 ( 0.7%) 1 72 +FieldDef 96 ( 1.0%) 2 48 +Arm 96 ( 1.0%) 2 48 +Stmt 96 ( 1.0%) 3 32 +FnDecl 120 ( 1.2%) 3 40 +Lifetime 128 ( 1.3%) 4 32 +Variant 160 ( 1.6%) 2 80 +ImplItem 176 ( 1.8%) 2 88 +GenericBound 192 ( 2.0%) 4 48 +TraitItem 192 ( 2.0%) 2 96 +WherePredicate 216 ( 2.2%) 3 72 +Block 288 ( 3.0%) 6 48 +QPath 408 ( 4.2%) 17 24 +Pat 440 ( 4.5%) 5 88 +Attribute 608 ( 6.2%) 4 152 +Expr 672 ( 6.9%) 12 56 +Item 960 ( 9.9%) 12 80 +Ty 1_152 (11.8%) 16 72 +Path 1_296 (13.3%) 27 48 +PathSegment 2_240 (23.0%) 40 56 +---------------------------------------------------------------- +Total 9_736 + diff --git a/src/test/ui/std-backtrace.rs b/src/test/ui/std-backtrace.rs index 07de066b558..3f8306baf8a 100644 --- a/src/test/ui/std-backtrace.rs +++ b/src/test/ui/std-backtrace.rs @@ -7,8 +7,6 @@ // compile-flags:-g // compile-flags:-Cstrip=none -#![feature(backtrace)] - use std::env; use std::process::Command; use std::str; diff --git a/src/test/ui/suggestions/as-ref.rs b/src/test/ui/suggestions/as-ref.rs index 46d9461538c..a0535344185 100644 --- a/src/test/ui/suggestions/as-ref.rs +++ b/src/test/ui/suggestions/as-ref.rs @@ -17,4 +17,11 @@ fn main() { // note: do not suggest because of `E: usize` let x: &Result<usize, usize> = &Ok(3); let y: Result<&usize, usize> = x; //~ ERROR mismatched types [E0308] + + let multiple_ref_opt = &&Some(Foo); + multiple_ref_opt.map(|arg| takes_ref(arg)); //~ ERROR mismatched types [E0308] + multiple_ref_opt.and_then(|arg| Some(takes_ref(arg))); //~ ERROR mismatched types [E0308] + let multiple_ref_result = &&Ok(Foo); + multiple_ref_result.map(|arg| takes_ref(arg)); //~ ERROR mismatched types [E0308] + multiple_ref_result.and_then(|arg| Ok(takes_ref(arg))); //~ ERROR mismatched types [E0308] } diff --git a/src/test/ui/suggestions/as-ref.stderr b/src/test/ui/suggestions/as-ref.stderr index 1efd1b317b7..deafa9f48d4 100644 --- a/src/test/ui/suggestions/as-ref.stderr +++ b/src/test/ui/suggestions/as-ref.stderr @@ -97,6 +97,66 @@ LL | let y: Result<&usize, usize> = x; = note: expected enum `Result<&usize, usize>` found reference `&Result<usize, usize>` -error: aborting due to 7 previous errors +error[E0308]: mismatched types + --> $DIR/as-ref.rs:22:42 + | +LL | multiple_ref_opt.map(|arg| takes_ref(arg)); + | --- --------- ^^^ expected `&Foo`, found struct `Foo` + | | | + | | arguments to this function are incorrect + | help: consider using `as_ref` instead: `as_ref().map` + | +note: function defined here + --> $DIR/as-ref.rs:3:4 + | +LL | fn takes_ref(_: &Foo) {} + | ^^^^^^^^^ ------- + +error[E0308]: mismatched types + --> $DIR/as-ref.rs:23:52 + | +LL | multiple_ref_opt.and_then(|arg| Some(takes_ref(arg))); + | -------- --------- ^^^ expected `&Foo`, found struct `Foo` + | | | + | | arguments to this function are incorrect + | help: consider using `as_ref` instead: `as_ref().and_then` + | +note: function defined here + --> $DIR/as-ref.rs:3:4 + | +LL | fn takes_ref(_: &Foo) {} + | ^^^^^^^^^ ------- + +error[E0308]: mismatched types + --> $DIR/as-ref.rs:25:45 + | +LL | multiple_ref_result.map(|arg| takes_ref(arg)); + | --- --------- ^^^ expected `&Foo`, found struct `Foo` + | | | + | | arguments to this function are incorrect + | help: consider using `as_ref` instead: `as_ref().map` + | +note: function defined here + --> $DIR/as-ref.rs:3:4 + | +LL | fn takes_ref(_: &Foo) {} + | ^^^^^^^^^ ------- + +error[E0308]: mismatched types + --> $DIR/as-ref.rs:26:53 + | +LL | multiple_ref_result.and_then(|arg| Ok(takes_ref(arg))); + | -------- --------- ^^^ expected `&Foo`, found struct `Foo` + | | | + | | arguments to this function are incorrect + | help: consider using `as_ref` instead: `as_ref().and_then` + | +note: function defined here + --> $DIR/as-ref.rs:3:4 + | +LL | fn takes_ref(_: &Foo) {} + | ^^^^^^^^^ ------- + +error: aborting due to 11 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/field-access-considering-privacy.rs b/src/test/ui/suggestions/field-access-considering-privacy.rs new file mode 100644 index 00000000000..3de06b21420 --- /dev/null +++ b/src/test/ui/suggestions/field-access-considering-privacy.rs @@ -0,0 +1,35 @@ +use a::TyCtxt; + +mod a { + use std::ops::Deref; + pub struct TyCtxt<'tcx> { + gcx: &'tcx GlobalCtxt<'tcx>, + } + + impl<'tcx> Deref for TyCtxt<'tcx> { + type Target = &'tcx GlobalCtxt<'tcx>; + + fn deref(&self) -> &Self::Target { + &self.gcx + } + } + + pub struct GlobalCtxt<'tcx> { + pub sess: &'tcx Session, + _t: &'tcx (), + } + + pub struct Session { + pub opts: (), + } +} + +mod b { + fn foo<'tcx>(tcx: crate::TyCtxt<'tcx>) { + tcx.opts; + //~^ ERROR no field `opts` on type `TyCtxt<'tcx>` + //~| HELP one of the expressions' fields has a field of the same name + } +} + +fn main() {} diff --git a/src/test/ui/suggestions/field-access-considering-privacy.stderr b/src/test/ui/suggestions/field-access-considering-privacy.stderr new file mode 100644 index 00000000000..cbf6f3d1002 --- /dev/null +++ b/src/test/ui/suggestions/field-access-considering-privacy.stderr @@ -0,0 +1,14 @@ +error[E0609]: no field `opts` on type `TyCtxt<'tcx>` + --> $DIR/field-access-considering-privacy.rs:29:13 + | +LL | tcx.opts; + | ^^^^ unknown field + | +help: one of the expressions' fields has a field of the same name + | +LL | tcx.sess.opts; + | +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0609`. diff --git a/src/test/ui/traits/alias/generic-default-in-dyn.rs b/src/test/ui/traits/alias/generic-default-in-dyn.rs new file mode 100644 index 00000000000..d44e1c2a975 --- /dev/null +++ b/src/test/ui/traits/alias/generic-default-in-dyn.rs @@ -0,0 +1,10 @@ +trait SendEqAlias<T> = PartialEq; +//~^ ERROR trait aliases are experimental + +struct Foo<T>(dyn SendEqAlias<T>); +//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393] + +struct Bar<T>(dyn SendEqAlias<T>, T); +//~^ ERROR the type parameter `Rhs` must be explicitly specified [E0393] + +fn main() {} diff --git a/src/test/ui/traits/alias/generic-default-in-dyn.stderr b/src/test/ui/traits/alias/generic-default-in-dyn.stderr new file mode 100644 index 00000000000..76a068e864a --- /dev/null +++ b/src/test/ui/traits/alias/generic-default-in-dyn.stderr @@ -0,0 +1,39 @@ +error[E0658]: trait aliases are experimental + --> $DIR/generic-default-in-dyn.rs:1:1 + | +LL | trait SendEqAlias<T> = PartialEq; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #41517 <https://github.com/rust-lang/rust/issues/41517> for more information + = help: add `#![feature(trait_alias)]` to the crate attributes to enable + +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/generic-default-in-dyn.rs:4:19 + | +LL | struct Foo<T>(dyn SendEqAlias<T>); + | ^^^^^^^^^^^^^^ missing reference to `Rhs` + | + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | +LL | pub trait PartialEq<Rhs: ?Sized = Self> { + | --------------------------------------- type parameter `Rhs` must be specified for this + | + = note: because of the default `Self` reference, type parameters must be specified on object types + +error[E0393]: the type parameter `Rhs` must be explicitly specified + --> $DIR/generic-default-in-dyn.rs:7:19 + | +LL | struct Bar<T>(dyn SendEqAlias<T>, T); + | ^^^^^^^^^^^^^^ missing reference to `Rhs` + | + ::: $SRC_DIR/core/src/cmp.rs:LL:COL + | +LL | pub trait PartialEq<Rhs: ?Sized = Self> { + | --------------------------------------- type parameter `Rhs` must be specified for this + | + = note: because of the default `Self` reference, type parameters must be specified on object types + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0393, E0658. +For more information about an error, try `rustc --explain E0393`. diff --git a/src/test/ui/traits/alias/self-in-generics.rs b/src/test/ui/traits/alias/self-in-generics.rs new file mode 100644 index 00000000000..6b99431f5bb --- /dev/null +++ b/src/test/ui/traits/alias/self-in-generics.rs @@ -0,0 +1,8 @@ +#![feature(trait_alias)] + +pub trait SelfInput = Fn(&mut Self); + +pub fn f(_f: &dyn SelfInput) {} +//~^ ERROR the trait alias `SelfInput` cannot be made into an object [E0038] + +fn main() {} diff --git a/src/test/ui/traits/alias/self-in-generics.stderr b/src/test/ui/traits/alias/self-in-generics.stderr new file mode 100644 index 00000000000..a1056872ea6 --- /dev/null +++ b/src/test/ui/traits/alias/self-in-generics.stderr @@ -0,0 +1,11 @@ +error[E0038]: the trait alias `SelfInput` cannot be made into an object + --> $DIR/self-in-generics.rs:5:19 + | +LL | pub fn f(_f: &dyn SelfInput) {} + | ^^^^^^^^^ + | + = note: it cannot use `Self` as a type parameter in a supertrait or `where`-clause + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0038`. diff --git a/src/test/ui/unspecified-self-in-trait-ref.rs b/src/test/ui/traits/unspecified-self-in-trait-ref.rs index 158b5a98557..158b5a98557 100644 --- a/src/test/ui/unspecified-self-in-trait-ref.rs +++ b/src/test/ui/traits/unspecified-self-in-trait-ref.rs diff --git a/src/test/ui/unspecified-self-in-trait-ref.stderr b/src/test/ui/traits/unspecified-self-in-trait-ref.stderr index 7869176bb3a..7869176bb3a 100644 --- a/src/test/ui/unspecified-self-in-trait-ref.stderr +++ b/src/test/ui/traits/unspecified-self-in-trait-ref.stderr diff --git a/src/test/ui/typeck/issue-100246.rs b/src/test/ui/typeck/issue-100246.rs new file mode 100644 index 00000000000..8f0b34bab0c --- /dev/null +++ b/src/test/ui/typeck/issue-100246.rs @@ -0,0 +1,30 @@ +#![recursion_limit = "5"] // To reduce noise + +//expect incompatible type error when ambiguous traits are in scope +//and not an overflow error on the span in the main function. + +struct Ratio<T>(T); + +pub trait Pow { + fn pow(self) -> Self; +} + +impl<'a, T> Pow for &'a Ratio<T> +where + &'a T: Pow, +{ + fn pow(self) -> Self { + self + } +} + +fn downcast<'a, W: ?Sized>() -> std::io::Result<&'a W> { + todo!() +} + +struct Other; + +fn main() -> std::io::Result<()> { + let other: Other = downcast()?;//~ERROR 28:24: 28:35: `?` operator has incompatible types + Ok(()) +} diff --git a/src/test/ui/typeck/issue-100246.stderr b/src/test/ui/typeck/issue-100246.stderr new file mode 100644 index 00000000000..8b77de94e89 --- /dev/null +++ b/src/test/ui/typeck/issue-100246.stderr @@ -0,0 +1,13 @@ +error[E0308]: `?` operator has incompatible types + --> $DIR/issue-100246.rs:28:24 + | +LL | let other: Other = downcast()?; + | ^^^^^^^^^^^ expected struct `Other`, found reference + | + = note: `?` operator cannot convert from `&_` to `Other` + = note: expected struct `Other` + found reference `&_` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 4fd148c47e733770c537efac5220744945d572e +Subproject efd4ca3dc0b89929dc8c5f5c023d25978d76cb6 diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 2278a8dc16b..380cd451987 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -965,7 +965,7 @@ Released 2021-09-09 [#7407](https://github.com/rust-lang/rust-clippy/pull/7407) * [`redundant_allocation`]: Now additionally supports the `Arc<>` type [#7308](https://github.com/rust-lang/rust-clippy/pull/7308) -* [`blacklisted_name`]: Now allows blacklisted names in test code +* [`disallowed_names`]: Now allows disallowed names in test code [#7379](https://github.com/rust-lang/rust-clippy/pull/7379) * [`redundant_closure`]: Suggests `&mut` for `FnMut` [#7437](https://github.com/rust-lang/rust-clippy/pull/7437) @@ -2066,7 +2066,7 @@ Released 2020-08-27 [#5692](https://github.com/rust-lang/rust-clippy/pull/5692) * [`if_same_then_else`]: Don't assume multiplication is always commutative [#5702](https://github.com/rust-lang/rust-clippy/pull/5702) -* [`blacklisted_name`]: Remove `bar` from the default configuration +* [`disallowed_names`]: Remove `bar` from the default configuration [#5712](https://github.com/rust-lang/rust-clippy/pull/5712) * [`redundant_pattern_matching`]: Avoid suggesting non-`const fn` calls in const contexts [#5724](https://github.com/rust-lang/rust-clippy/pull/5724) @@ -3522,6 +3522,7 @@ Released 2018-09-13 [`derive_partial_eq_without_eq`]: https://rust-lang.github.io/rust-clippy/master/index.html#derive_partial_eq_without_eq [`disallowed_method`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_method [`disallowed_methods`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_methods +[`disallowed_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names [`disallowed_script_idents`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_script_idents [`disallowed_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_type [`disallowed_types`]: https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_types @@ -3685,6 +3686,7 @@ Released 2018-09-13 [`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find [`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map [`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten +[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive @@ -3816,11 +3818,13 @@ Released 2018-09-13 [`or_then_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#or_then_unwrap [`out_of_bounds_indexing`]: https://rust-lang.github.io/rust-clippy/master/index.html#out_of_bounds_indexing [`overflow_check_conditional`]: https://rust-lang.github.io/rust-clippy/master/index.html#overflow_check_conditional +[`overly_complex_bool_expr`]: https://rust-lang.github.io/rust-clippy/master/index.html#overly_complex_bool_expr [`panic`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic [`panic_in_result_fn`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_in_result_fn [`panic_params`]: https://rust-lang.github.io/rust-clippy/master/index.html#panic_params [`panicking_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#panicking_unwrap [`partialeq_ne_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_ne_impl +[`partialeq_to_none`]: https://rust-lang.github.io/rust-clippy/master/index.html#partialeq_to_none [`path_buf_push_overwrite`]: https://rust-lang.github.io/rust-clippy/master/index.html#path_buf_push_overwrite [`pattern_type_mismatch`]: https://rust-lang.github.io/rust-clippy/master/index.html#pattern_type_mismatch [`possible_missing_comma`]: https://rust-lang.github.io/rust-clippy/master/index.html#possible_missing_comma diff --git a/src/tools/clippy/CONTRIBUTING.md b/src/tools/clippy/CONTRIBUTING.md index 6e15133d267..28b4cfd5f09 100644 --- a/src/tools/clippy/CONTRIBUTING.md +++ b/src/tools/clippy/CONTRIBUTING.md @@ -30,10 +30,10 @@ All contributors are expected to follow the [Rust Code of Conduct]. ## The Clippy book If you're new to Clippy and don't know where to start the [Clippy book] includes -a developer guide and is a good place to start your journey. +a [developer guide] and is a good place to start your journey. -<!-- FIXME: Link to the deployed book, once it is deployed through CI --> -[Clippy book]: book/src +[Clippy book]: https://doc.rust-lang.org/nightly/clippy/index.html +[developer guide]: https://doc.rust-lang.org/nightly/clippy/development/index.html ## High level approach diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index 1c875c3adcf..b7e136ce9b2 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.64" +version = "0.1.65" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index 2c3defeaa83..1193771ff73 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -144,7 +144,7 @@ value` mapping e.g. ```toml avoid-breaking-exported-api = false -blacklisted-names = ["toto", "tata", "titi"] +disallowed-names = ["toto", "tata", "titi"] cognitive-complexity-threshold = 30 ``` diff --git a/src/tools/clippy/book/src/configuration.md b/src/tools/clippy/book/src/configuration.md index 6e295ac3181..77f1d2e8797 100644 --- a/src/tools/clippy/book/src/configuration.md +++ b/src/tools/clippy/book/src/configuration.md @@ -7,7 +7,7 @@ basic `variable = value` mapping eg. ```toml avoid-breaking-exported-api = false -blacklisted-names = ["toto", "tata", "titi"] +disallowed-names = ["toto", "tata", "titi"] cognitive-complexity-threshold = 30 ``` diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs index 03d2ef3d19e..10a8f31f457 100644 --- a/src/tools/clippy/clippy_dev/src/new_lint.rs +++ b/src/tools/clippy/clippy_dev/src/new_lint.rs @@ -438,7 +438,7 @@ fn setup_mod_file(path: &Path, lint: &LintData<'_>) -> io::Result<&'static str> let mut lint_context = None; let mut iter = rustc_lexer::tokenize(&file_contents).map(|t| { - let range = offset..offset + t.len; + let range = offset..offset + t.len as usize; offset = range.end; LintDeclSearchResult { diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index aed38bc2817..05e79a24188 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -836,7 +836,7 @@ pub(crate) struct LintDeclSearchResult<'a> { fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) { let mut offset = 0usize; let mut iter = tokenize(contents).map(|t| { - let range = offset..offset + t.len; + let range = offset..offset + t.len as usize; offset = range.end; LintDeclSearchResult { @@ -899,7 +899,7 @@ fn parse_contents(contents: &str, module: &str, lints: &mut Vec<Lint>) { fn parse_deprecated_contents(contents: &str, lints: &mut Vec<DeprecatedLint>) { let mut offset = 0usize; let mut iter = tokenize(contents).map(|t| { - let range = offset..offset + t.len; + let range = offset..offset + t.len as usize; offset = range.end; LintDeclSearchResult { @@ -946,7 +946,7 @@ fn parse_renamed_contents(contents: &str, lints: &mut Vec<RenamedLint>) { for line in contents.lines() { let mut offset = 0usize; let mut iter = tokenize(line).map(|t| { - let range = offset..offset + t.len; + let range = offset..offset + t.len as usize; offset = range.end; LintDeclSearchResult { diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 79a56dc405d..738562ef855 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_lints" -version = "0.1.64" +version = "0.1.65" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs index 4caab623090..6a6554f968b 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs @@ -53,13 +53,14 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { if result_type_with_refs != result_type { return; } else if let Res::Local(binding_id) = path_res(cx, recv) - && local_used_after_expr(cx, binding_id, recv) { + && local_used_after_expr(cx, binding_id, recv) + { return; } } let mut app = Applicability::MachineApplicable; match method_segment.ident.as_str() { - "is_ok" if has_debug_impl(cx, substs.type_at(1)) => { + "is_ok" if type_suitable_to_unwrap(cx, substs.type_at(1)) => { span_lint_and_sugg( cx, ASSERTIONS_ON_RESULT_STATES, @@ -73,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates { app, ); } - "is_err" if has_debug_impl(cx, substs.type_at(0)) => { + "is_err" if type_suitable_to_unwrap(cx, substs.type_at(0)) => { span_lint_and_sugg( cx, ASSERTIONS_ON_RESULT_STATES, @@ -99,3 +100,7 @@ fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { .get_diagnostic_item(sym::Debug) .map_or(false, |debug| implements_trait(cx, ty, debug, &[])) } + +fn type_suitable_to_unwrap<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { + has_debug_impl(cx, ty) && !ty.is_unit() && !ty.is_never() +} diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 526ee2f891a..6eb78d21e82 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -64,7 +64,7 @@ declare_clippy_lint! { /// if a {} /// ``` #[clippy::version = "pre 1.29.0"] - pub LOGIC_BUG, + pub OVERLY_COMPLEX_BOOL_EXPR, correctness, "boolean expressions that contain terminals which can be eliminated" } @@ -72,7 +72,7 @@ declare_clippy_lint! { // For each pairs, both orders are considered. const METHODS_WITH_NEGATION: [(&str, &str); 2] = [("is_some", "is_none"), ("is_err", "is_ok")]; -declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, LOGIC_BUG]); +declare_lint_pass!(NonminimalBool => [NONMINIMAL_BOOL, OVERLY_COMPLEX_BOOL_EXPR]); impl<'tcx> LateLintPass<'tcx> for NonminimalBool { fn check_fn( @@ -396,7 +396,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> { if stats.terminals[i] != 0 && simplified_stats.terminals[i] == 0 { span_lint_hir_and_then( self.cx, - LOGIC_BUG, + OVERLY_COMPLEX_BOOL_EXPR, e.hir_id, e.span, "this boolean expression contains a logic bug", diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs index 64ea326b75a..6426e8c25ac 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs @@ -37,7 +37,7 @@ pub(super) fn check( span, &format!("casting the result of `{cast_from}::abs()` to {cast_to}"), "replace with", - format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..")), + format!("{}.unsigned_abs()", Sugg::hir(cx, &args[0], "..").maybe_par()), Applicability::MachineApplicable, ); } diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs index 17fc81951f9..37b2fdcff09 100644 --- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs +++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs @@ -270,10 +270,7 @@ fn get_types_from_cast<'a>( let limit_from: Option<(&Expr<'_>, &str)> = call_from_cast.or_else(|| { if_chain! { // `from_type::from, to_type::max_value()` - if let ExprKind::Call(from_func, args) = &expr.kind; - // `to_type::max_value()` - if args.len() == 1; - if let limit = &args[0]; + if let ExprKind::Call(from_func, [limit]) = &expr.kind; // `from_type::from` if let ExprKind::Path(ref path) = &from_func.kind; if let Some(from_sym) = get_implementing_type(path, INTS, "from"); diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs index 18d34370a7b..878248a6bdc 100644 --- a/src/tools/clippy/clippy_lints/src/create_dir.rs +++ b/src/tools/clippy/clippy_lints/src/create_dir.rs @@ -34,7 +34,7 @@ declare_lint_pass!(CreateDir => [CREATE_DIR]); impl LateLintPass<'_> for CreateDir { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { - if let ExprKind::Call(func, args) = expr.kind; + if let ExprKind::Call(func, [arg, ..]) = expr.kind; if let ExprKind::Path(ref path) = func.kind; if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id(); if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR); @@ -45,7 +45,7 @@ impl LateLintPass<'_> for CreateDir { expr.span, "calling `std::fs::create_dir` where there may be a better way", "consider calling `std::fs::create_dir_all` instead", - format!("create_dir_all({})", snippet(cx, args[0].span, "..")), + format!("create_dir_all({})", snippet(cx, arg.span, "..")), Applicability::MaybeIncorrect, ) } diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs index d99a1aa2969..74f7df61177 100644 --- a/src/tools/clippy/clippy_lints/src/default.rs +++ b/src/tools/clippy/clippy_lints/src/default.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg}; use clippy_utils::source::snippet_with_macro_callsite; use clippy_utils::ty::{has_drop, is_copy}; -use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, match_def_path, paths}; +use clippy_utils::{ + any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths, +}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; @@ -94,6 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for Default { if let QPath::Resolved(None, _path) = qpath; let expr_ty = cx.typeck_results().expr_ty(expr); if let ty::Adt(def, ..) = expr_ty.kind(); + if !is_from_proc_macro(cx, expr); then { // TODO: Work out a way to put "whatever the imported way of referencing // this type in this file" rather than a fully-qualified type. diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index a90f894a7b1..5d41c63928d 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1,7 +1,7 @@ use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; use clippy_utils::sugg::has_enclosing_paren; -use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, variant_of_res}; +use clippy_utils::ty::{expr_sig, peel_mid_ty_refs, ty_sig, variant_of_res}; use clippy_utils::{get_parent_expr, is_lint_allowed, path_to_local, walk_to_expr_usage}; use rustc_ast::util::parser::{PREC_POSTFIX, PREC_PREFIX}; use rustc_data_structures::fx::FxIndexMap; @@ -15,9 +15,9 @@ use rustc_hir::{ use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow, AutoBorrowMutability}; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable, TypeckResults}; +use rustc_middle::ty::{self, Binder, BoundVariableKind, List, Ty, TyCtxt, TypeVisitable, TypeckResults}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::{symbol::sym, Span, Symbol}; +use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP}; use rustc_trait_selection::infer::InferCtxtExt; declare_clippy_lint! { @@ -183,24 +183,24 @@ enum State { }, DerefedBorrow(DerefedBorrow), ExplicitDeref { - // Span and id of the top-level deref expression if the parent expression is a borrow. - deref_span_id: Option<(Span, HirId)>, + mutability: Option<Mutability>, }, ExplicitDerefField { name: Symbol, }, Reborrow { - deref_span: Span, - deref_hir_id: HirId, + mutability: Mutability, + }, + Borrow { + mutability: Mutability, }, - Borrow, } // A reference operation considered by this lint pass enum RefOp { Method(Mutability), Deref, - AddrOf, + AddrOf(Mutability), } struct RefPat { @@ -263,7 +263,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { )); } else if position.is_deref_stable() { self.state = Some(( - State::ExplicitDeref { deref_span_id: None }, + State::ExplicitDeref { mutability: None }, StateData { span: expr.span, hir_id: expr.hir_id, position }, )); } @@ -289,7 +289,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { }, )); }, - RefOp::AddrOf => { + RefOp::AddrOf(mutability) => { // Find the number of times the borrow is auto-derefed. let mut iter = adjustments.iter(); let mut deref_count = 0usize; @@ -357,9 +357,13 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { }), StateData { span: expr.span, hir_id: expr.hir_id, position }, )); - } else if position.is_deref_stable() { + } else if position.is_deref_stable() + // Auto-deref doesn't combine with other adjustments + && next_adjust.map_or(true, |a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) + && iter.all(|a| matches!(a.kind, Adjust::Deref(_) | Adjust::Borrow(_))) + { self.state = Some(( - State::Borrow, + State::Borrow { mutability }, StateData { span: expr.span, hir_id: expr.hir_id, @@ -395,7 +399,7 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { data, )); }, - (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) if state.count != 0 => { + (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(_)) if state.count != 0 => { self.state = Some(( State::DerefedBorrow(DerefedBorrow { count: state.count - 1, @@ -404,12 +408,12 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { data, )); }, - (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf) => { + (Some((State::DerefedBorrow(state), data)), RefOp::AddrOf(mutability)) => { let position = data.position; report(cx, expr, State::DerefedBorrow(state), data); if position.is_deref_stable() { self.state = Some(( - State::Borrow, + State::Borrow { mutability }, StateData { span: expr.span, hir_id: expr.hir_id, @@ -430,43 +434,28 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing { )); } else if position.is_deref_stable() { self.state = Some(( - State::ExplicitDeref { deref_span_id: None }, + State::ExplicitDeref { mutability: None }, StateData { span: expr.span, hir_id: expr.hir_id, position }, )); } }, - (Some((State::Borrow, data)), RefOp::Deref) => { + (Some((State::Borrow { mutability }, data)), RefOp::Deref) => { if typeck.expr_ty(sub_expr).is_ref() { - self.state = Some(( - State::Reborrow { - deref_span: expr.span, - deref_hir_id: expr.hir_id, - }, - data, - )); + self.state = Some((State::Reborrow { mutability }, data)); } else { self.state = Some(( State::ExplicitDeref { - deref_span_id: Some((expr.span, expr.hir_id)), + mutability: Some(mutability), }, data, )); } }, - ( - Some(( - State::Reborrow { - deref_span, - deref_hir_id, - }, - data, - )), - RefOp::Deref, - ) => { + (Some((State::Reborrow { mutability }, data)), RefOp::Deref) => { self.state = Some(( State::ExplicitDeref { - deref_span_id: Some((deref_span, deref_hir_id)), + mutability: Some(mutability), }, data, )); @@ -573,7 +562,7 @@ fn try_parse_ref_op<'tcx>( ExprKind::Unary(UnOp::Deref, sub_expr) if !typeck.expr_ty(sub_expr).is_unsafe_ptr() => { return Some((RefOp::Deref, sub_expr)); }, - ExprKind::AddrOf(BorrowKind::Ref, _, sub_expr) => return Some((RefOp::AddrOf, sub_expr)), + ExprKind::AddrOf(BorrowKind::Ref, mutability, sub_expr) => return Some((RefOp::AddrOf(mutability), sub_expr)), _ => return None, }; if tcx.is_diagnostic_item(sym::deref_method, def_id) { @@ -609,18 +598,21 @@ enum Position { Postfix, Deref, /// Any other location which will trigger auto-deref to a specific time. - DerefStable(i8), + /// Contains the precedence of the parent expression and whether the target type is sized. + DerefStable(i8, bool), /// Any other location which will trigger auto-reborrowing. + /// Contains the precedence of the parent expression. ReborrowStable(i8), + /// Contains the precedence of the parent expression. Other(i8), } impl Position { fn is_deref_stable(self) -> bool { - matches!(self, Self::DerefStable(_)) + matches!(self, Self::DerefStable(..)) } fn is_reborrow_stable(self) -> bool { - matches!(self, Self::DerefStable(_) | Self::ReborrowStable(_)) + matches!(self, Self::DerefStable(..) | Self::ReborrowStable(_)) } fn can_auto_borrow(self) -> bool { @@ -628,7 +620,7 @@ impl Position { } fn lint_explicit_deref(self) -> bool { - matches!(self, Self::Other(_) | Self::DerefStable(_) | Self::ReborrowStable(_)) + matches!(self, Self::Other(_) | Self::DerefStable(..) | Self::ReborrowStable(_)) } fn precedence(self) -> i8 { @@ -639,7 +631,7 @@ impl Position { | Self::FieldAccess(_) | Self::Postfix => PREC_POSTFIX, Self::Deref => PREC_PREFIX, - Self::DerefStable(p) | Self::ReborrowStable(p) | Self::Other(p) => p, + Self::DerefStable(p, _) | Self::ReborrowStable(p) | Self::Other(p) => p, } } } @@ -659,7 +651,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & } match parent { Node::Local(Local { ty: Some(ty), span, .. }) if span.ctxt() == ctxt => { - Some(binding_ty_auto_deref_stability(ty, precedence)) + Some(binding_ty_auto_deref_stability(cx, ty, precedence, List::empty())) }, Node::Item(&Item { kind: ItemKind::Static(..) | ItemKind::Const(..), @@ -680,11 +672,7 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .. }) if span.ctxt() == ctxt => { let ty = cx.tcx.type_of(def_id); - Some(if ty.is_ref() { - Position::DerefStable(precedence) - } else { - Position::Other(precedence) - }) + Some(ty_auto_deref_stability(cx, ty, precedence).position_for_result(cx)) }, Node::Item(&Item { @@ -705,45 +693,38 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & span, .. }) if span.ctxt() == ctxt => { - let output = cx.tcx.fn_sig(def_id.to_def_id()).skip_binder().output(); - Some(if !output.is_ref() { - Position::Other(precedence) - } else if output.has_placeholders() || output.has_opaque_types() { - Position::ReborrowStable(precedence) - } else { - Position::DerefStable(precedence) - }) + let output = cx + .tcx + .erase_late_bound_regions(cx.tcx.fn_sig(def_id.to_def_id()).output()); + Some(ty_auto_deref_stability(cx, output, precedence).position_for_result(cx)) }, Node::Expr(parent) if parent.span.ctxt() == ctxt => match parent.kind { ExprKind::Ret(_) => { let owner_id = cx.tcx.hir().body_owner(cx.enclosing_body.unwrap()); Some( - if let Node::Expr(Expr { - kind: ExprKind::Closure(&Closure { fn_decl, .. }), - .. - }) = cx.tcx.hir().get(owner_id) + if let Node::Expr( + closure_expr @ Expr { + kind: ExprKind::Closure(closure), + .. + }, + ) = cx.tcx.hir().get(owner_id) { - match fn_decl.output { - FnRetTy::Return(ty) => binding_ty_auto_deref_stability(ty, precedence), - FnRetTy::DefaultReturn(_) => Position::Other(precedence), - } + closure_result_position(cx, closure, cx.typeck_results().expr_ty(closure_expr), precedence) } else { let output = cx .tcx - .fn_sig(cx.tcx.hir().local_def_id(owner_id)) - .skip_binder() - .output(); - if !output.is_ref() { - Position::Other(precedence) - } else if output.has_placeholders() || output.has_opaque_types() { - Position::ReborrowStable(precedence) - } else { - Position::DerefStable(precedence) - } + .erase_late_bound_regions(cx.tcx.fn_sig(cx.tcx.hir().local_def_id(owner_id)).output()); + ty_auto_deref_stability(cx, output, precedence).position_for_result(cx) }, ) }, + ExprKind::Closure(closure) => Some(closure_result_position( + cx, + closure, + cx.typeck_results().expr_ty(parent), + precedence, + )), ExprKind::Call(func, _) if func.hir_id == child_id => { (child_id == e.hir_id).then_some(Position::Callee) }, @@ -755,8 +736,9 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .map(|(hir_ty, ty)| match hir_ty { // Type inference for closures can depend on how they're called. Only go by the explicit // types here. - Some(ty) => binding_ty_auto_deref_stability(ty, precedence), - None => param_auto_deref_stability(ty.skip_binder(), precedence), + Some(hir_ty) => binding_ty_auto_deref_stability(cx, hir_ty, precedence, ty.bound_vars()), + None => ty_auto_deref_stability(cx, cx.tcx.erase_late_bound_regions(ty), precedence) + .position_for_arg(), }), ExprKind::MethodCall(_, args, _) => { let id = cx.typeck_results().type_dependent_def_id(parent.hir_id).unwrap(); @@ -797,7 +779,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & Position::MethodReceiver } } else { - param_auto_deref_stability(cx.tcx.fn_sig(id).skip_binder().inputs()[i], precedence) + ty_auto_deref_stability( + cx, + cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).input(i)), + precedence, + ) + .position_for_arg() } }) }, @@ -808,7 +795,9 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & .find(|f| f.expr.hir_id == child_id) .zip(variant) .and_then(|(field, variant)| variant.fields.iter().find(|f| f.name == field.ident.name)) - .map(|field| param_auto_deref_stability(cx.tcx.type_of(field.did), precedence)) + .map(|field| { + ty_auto_deref_stability(cx, cx.tcx.type_of(field.did), precedence).position_for_arg() + }) }, ExprKind::Field(child, name) if child.hir_id == e.hir_id => Some(Position::FieldAccess(name.name)), ExprKind::Unary(UnOp::Deref, child) if child.hir_id == e.hir_id => Some(Position::Deref), @@ -831,6 +820,26 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & (position, adjustments) } +fn closure_result_position<'tcx>( + cx: &LateContext<'tcx>, + closure: &'tcx Closure<'_>, + ty: Ty<'tcx>, + precedence: i8, +) -> Position { + match closure.fn_decl.output { + FnRetTy::Return(hir_ty) => { + if let Some(sig) = ty_sig(cx, ty) + && let Some(output) = sig.output() + { + binding_ty_auto_deref_stability(cx, hir_ty, precedence, output.bound_vars()) + } else { + Position::Other(precedence) + } + }, + FnRetTy::DefaultReturn(_) => Position::Other(precedence), + } +} + // Checks the stability of auto-deref when assigned to a binding with the given explicit type. // // e.g. @@ -840,7 +849,12 @@ fn walk_parents<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> (Position, & // // Here `y1` and `y2` would resolve to different types, so the type `&Box<_>` is not stable when // switching to auto-dereferencing. -fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position { +fn binding_ty_auto_deref_stability<'tcx>( + cx: &LateContext<'tcx>, + ty: &'tcx hir::Ty<'_>, + precedence: i8, + binder_args: &'tcx List<BoundVariableKind>, +) -> Position { let TyKind::Rptr(_, ty) = &ty.kind else { return Position::Other(precedence); }; @@ -870,21 +884,33 @@ fn binding_ty_auto_deref_stability(ty: &hir::Ty<'_>, precedence: i8) -> Position { Position::ReborrowStable(precedence) } else { - Position::DerefStable(precedence) + Position::DerefStable( + precedence, + cx.tcx + .erase_late_bound_regions(Binder::bind_with_vars( + cx.typeck_results().node_type(ty.ty.hir_id), + binder_args, + )) + .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + ) } }, - TyKind::Slice(_) - | TyKind::Array(..) - | TyKind::BareFn(_) - | TyKind::Never + TyKind::Slice(_) => Position::DerefStable(precedence, false), + TyKind::Array(..) | TyKind::Ptr(_) | TyKind::BareFn(_) => Position::DerefStable(precedence, true), + TyKind::Never | TyKind::Tup(_) - | TyKind::Ptr(_) - | TyKind::TraitObject(..) - | TyKind::Path(_) => Position::DerefStable(precedence), - TyKind::OpaqueDef(..) - | TyKind::Infer - | TyKind::Typeof(..) - | TyKind::Err => Position::ReborrowStable(precedence), + | TyKind::Path(_) => Position::DerefStable( + precedence, + cx.tcx + .erase_late_bound_regions(Binder::bind_with_vars( + cx.typeck_results().node_type(ty.ty.hir_id), + binder_args, + )) + .is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + ), + TyKind::OpaqueDef(..) | TyKind::Infer | TyKind::Typeof(..) | TyKind::TraitObject(..) | TyKind::Err => { + Position::ReborrowStable(precedence) + }, }; } } @@ -920,10 +946,39 @@ fn ty_contains_infer(ty: &hir::Ty<'_>) -> bool { v.0 } +struct TyPosition<'tcx> { + position: Position, + ty: Option<Ty<'tcx>>, +} +impl From<Position> for TyPosition<'_> { + fn from(position: Position) -> Self { + Self { position, ty: None } + } +} +impl<'tcx> TyPosition<'tcx> { + fn new_deref_stable_for_result(precedence: i8, ty: Ty<'tcx>) -> Self { + Self { + position: Position::ReborrowStable(precedence), + ty: Some(ty), + } + } + fn position_for_result(self, cx: &LateContext<'tcx>) -> Position { + match (self.position, self.ty) { + (Position::ReborrowStable(precedence), Some(ty)) => { + Position::DerefStable(precedence, ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env)) + }, + (position, _) => position, + } + } + fn position_for_arg(self) -> Position { + self.position + } +} + // Checks whether a type is stable when switching to auto dereferencing, -fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position { +fn ty_auto_deref_stability<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, precedence: i8) -> TyPosition<'tcx> { let ty::Ref(_, mut ty, _) = *ty.kind() else { - return Position::Other(precedence); + return Position::Other(precedence).into(); }; loop { @@ -932,35 +987,38 @@ fn param_auto_deref_stability(ty: Ty<'_>, precedence: i8) -> Position { ty = ref_ty; continue; }, - ty::Infer(_) - | ty::Error(_) - | ty::Param(_) - | ty::Bound(..) - | ty::Opaque(..) - | ty::Placeholder(_) - | ty::Dynamic(..) => Position::ReborrowStable(precedence), - ty::Adt(..) if ty.has_placeholders() || ty.has_param_types_or_consts() => { - Position::ReborrowStable(precedence) + ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty), + ty::Infer(_) | ty::Error(_) | ty::Bound(..) | ty::Opaque(..) | ty::Placeholder(_) | ty::Dynamic(..) => { + Position::ReborrowStable(precedence).into() }, - ty::Adt(..) - | ty::Bool + ty::Adt(..) if ty.has_placeholders() || ty.has_opaque_types() => { + Position::ReborrowStable(precedence).into() + }, + ty::Adt(_, substs) if substs.has_param_types_or_consts() => { + TyPosition::new_deref_stable_for_result(precedence, ty) + }, + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) - | ty::Float(_) - | ty::Foreign(_) - | ty::Str | ty::Array(..) - | ty::Slice(..) + | ty::Float(_) | ty::RawPtr(..) + | ty::FnPtr(_) => Position::DerefStable(precedence, true).into(), + ty::Str | ty::Slice(..) => Position::DerefStable(precedence, false).into(), + ty::Adt(..) + | ty::Foreign(_) | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Closure(..) | ty::Generator(..) | ty::GeneratorWitness(..) + | ty::Closure(..) | ty::Never | ty::Tuple(_) - | ty::Projection(_) => Position::DerefStable(precedence), + | ty::Projection(_) => Position::DerefStable( + precedence, + ty.is_sized(cx.tcx.at(DUMMY_SP), cx.param_env.without_caller_bounds()), + ) + .into(), }; } } @@ -1040,34 +1098,64 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data diag.span_suggestion(data.span, "change this to", sugg, app); }); }, - State::ExplicitDeref { deref_span_id } => { - let (span, hir_id, precedence) = if let Some((span, hir_id)) = deref_span_id + State::ExplicitDeref { mutability } => { + if matches!( + expr.kind, + ExprKind::Block(..) + | ExprKind::ConstBlock(_) + | ExprKind::If(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + ) && matches!(data.position, Position::DerefStable(_, true)) + { + // Rustc bug: auto deref doesn't work on block expression when targeting sized types. + return; + } + + let (prefix, precedence) = if let Some(mutability) = mutability && !cx.typeck_results().expr_ty(expr).is_ref() { - (span, hir_id, PREC_PREFIX) + let prefix = match mutability { + Mutability::Not => "&", + Mutability::Mut => "&mut ", + }; + (prefix, 0) } else { - (data.span, data.hir_id, data.position.precedence()) + ("", data.position.precedence()) }; span_lint_hir_and_then( cx, EXPLICIT_AUTO_DEREF, - hir_id, - span, + data.hir_id, + data.span, "deref which would be done by auto-deref", |diag| { let mut app = Applicability::MachineApplicable; - let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, span.ctxt(), "..", &mut app); + let (snip, snip_is_macro) = snippet_with_context(cx, expr.span, data.span.ctxt(), "..", &mut app); let sugg = if !snip_is_macro && expr.precedence().order() < precedence && !has_enclosing_paren(&snip) { - format!("({})", snip) + format!("{}({})", prefix, snip) } else { - snip.into() + format!("{}{}", prefix, snip) }; - diag.span_suggestion(span, "try this", sugg, app); + diag.span_suggestion(data.span, "try this", sugg, app); }, ); }, State::ExplicitDerefField { .. } => { + if matches!( + expr.kind, + ExprKind::Block(..) + | ExprKind::ConstBlock(_) + | ExprKind::If(..) + | ExprKind::Loop(..) + | ExprKind::Match(..) + ) && matches!(data.position, Position::DerefStable(_, true)) + { + // Rustc bug: auto deref doesn't work on block expression when targeting sized types. + return; + } + span_lint_hir_and_then( cx, EXPLICIT_AUTO_DEREF, @@ -1081,7 +1169,7 @@ fn report<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, state: State, data }, ); }, - State::Borrow | State::Reborrow { .. } => (), + State::Borrow { .. } | State::Reborrow { .. } => (), } } diff --git a/src/tools/clippy/clippy_lints/src/blacklisted_name.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs index 1600fb25d89..6e6615f08ee 100644 --- a/src/tools/clippy/clippy_lints/src/blacklisted_name.rs +++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs @@ -6,7 +6,7 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; declare_clippy_lint! { /// ### What it does - /// Checks for usage of blacklisted names for variables, such + /// Checks for usage of disallowed names for variables, such /// as `foo`. /// /// ### Why is this bad? @@ -18,21 +18,21 @@ declare_clippy_lint! { /// let foo = 3.14; /// ``` #[clippy::version = "pre 1.29.0"] - pub BLACKLISTED_NAME, + pub DISALLOWED_NAMES, style, - "usage of a blacklisted/placeholder name" + "usage of a disallowed/placeholder name" } #[derive(Clone, Debug)] -pub struct BlacklistedName { - blacklist: FxHashSet<String>, +pub struct DisallowedNames { + disallow: FxHashSet<String>, test_modules_deep: u32, } -impl BlacklistedName { - pub fn new(blacklist: FxHashSet<String>) -> Self { +impl DisallowedNames { + pub fn new(disallow: FxHashSet<String>) -> Self { Self { - blacklist, + disallow, test_modules_deep: 0, } } @@ -42,9 +42,9 @@ impl BlacklistedName { } } -impl_lint_pass!(BlacklistedName => [BLACKLISTED_NAME]); +impl_lint_pass!(DisallowedNames => [DISALLOWED_NAMES]); -impl<'tcx> LateLintPass<'tcx> for BlacklistedName { +impl<'tcx> LateLintPass<'tcx> for DisallowedNames { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { if is_test_module_or_function(cx.tcx, item) { self.test_modules_deep = self.test_modules_deep.saturating_add(1); @@ -58,12 +58,12 @@ impl<'tcx> LateLintPass<'tcx> for BlacklistedName { } if let PatKind::Binding(.., ident, _) = pat.kind { - if self.blacklist.contains(&ident.name.to_string()) { + if self.disallow.contains(&ident.name.to_string()) { span_lint( cx, - BLACKLISTED_NAME, + DISALLOWED_NAMES, ident.span, - &format!("use of a blacklisted/placeholder name `{}`", ident.name), + &format!("use of a disallowed/placeholder name `{}`", ident.name), ); } } diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs index a33ef5ce6e3..0f1d701865e 100644 --- a/src/tools/clippy/clippy_lints/src/double_parens.rs +++ b/src/tools/clippy/clippy_lints/src/double_parens.rs @@ -61,9 +61,8 @@ impl EarlyLintPass for DoubleParens { } } }, - ExprKind::MethodCall(_, ref params, _) => { - if params.len() == 2 { - let param = ¶ms[1]; + ExprKind::MethodCall(_, _, ref params, _) => { + if let [ref param] = params[..] { if let ExprKind::Paren(_) = param.kind { span_lint(cx, DOUBLE_PARENS, param.span, msg); } diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index db0166da57f..01cefe4af85 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note}; +use clippy_utils::is_span_if; use clippy_utils::source::snippet_opt; use if_chain::if_chain; use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp}; @@ -297,12 +298,11 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) { fn check_missing_else(cx: &EarlyContext<'_>, first: &Expr, second: &Expr) { if_chain! { if !first.span.from_expansion() && !second.span.from_expansion(); - if let ExprKind::If(cond_expr, ..) = &first.kind; + if matches!(first.kind, ExprKind::If(..)); if is_block(second) || is_if(second); // Proc-macros can give weird spans. Make sure this is actually an `if`. - if let Some(if_snip) = snippet_opt(cx, first.span.until(cond_expr.span)); - if if_snip.starts_with("if"); + if is_span_if(cx, first.span); // If there is a line break between the two expressions, don't lint. // If there is a non-whitespace character, this span came from a proc-macro. diff --git a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs index 57b07513205..74941d817be 100644 --- a/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs +++ b/src/tools/clippy/clippy_lints/src/from_str_radix_10.rs @@ -46,7 +46,7 @@ declare_lint_pass!(FromStrRadix10 => [FROM_STR_RADIX_10]); impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { fn check_expr(&mut self, cx: &LateContext<'tcx>, exp: &Expr<'tcx>) { if_chain! { - if let ExprKind::Call(maybe_path, arguments) = &exp.kind; + if let ExprKind::Call(maybe_path, [src, radix]) = &exp.kind; if let ExprKind::Path(QPath::TypeRelative(ty, pathseg)) = &maybe_path.kind; // check if the first part of the path is some integer primitive @@ -60,20 +60,19 @@ impl<'tcx> LateLintPass<'tcx> for FromStrRadix10 { if pathseg.ident.name.as_str() == "from_str_radix"; // check if the second argument is a primitive `10` - if arguments.len() == 2; - if let ExprKind::Lit(lit) = &arguments[1].kind; + if let ExprKind::Lit(lit) = &radix.kind; if let rustc_ast::ast::LitKind::Int(10, _) = lit.node; then { - let expr = if let ExprKind::AddrOf(_, _, expr) = &arguments[0].kind { + let expr = if let ExprKind::AddrOf(_, _, expr) = &src.kind { let ty = cx.typeck_results().expr_ty(expr); if is_ty_stringish(cx, ty) { expr } else { - &arguments[0] + &src } } else { - &arguments[0] + &src }; let sugg = Sugg::hir_with_applicability( 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 0ba9b7ae7e5..01082cc8eeb 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_all.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_all.rs @@ -15,11 +15,10 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE), LintId::of(await_holding_invalid::AWAIT_HOLDING_LOCK), LintId::of(await_holding_invalid::AWAIT_HOLDING_REFCELL_REF), - LintId::of(blacklisted_name::BLACKLISTED_NAME), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), - LintId::of(booleans::LOGIC_BUG), LintId::of(booleans::NONMINIMAL_BOOL), + LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR), LintId::of(borrow_deref_ref::BORROW_DEREF_REF), LintId::of(bytes_count_to_len::BYTES_COUNT_TO_LEN), LintId::of(casts::CAST_ABS_TO_UNSIGNED), @@ -46,6 +45,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(derive::DERIVE_ORD_XOR_PARTIAL_ORD), LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), + LintId::of(disallowed_names::DISALLOWED_NAMES), LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(doc::MISSING_SAFETY_DOC), LintId::of(doc::NEEDLESS_DOCTEST_MAIN), @@ -144,7 +144,6 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(matches::MATCH_STR_CASE_MISMATCH), LintId::of(matches::NEEDLESS_MATCH), LintId::of(matches::REDUNDANT_PATTERN_MATCHING), - LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), LintId::of(matches::SINGLE_MATCH), LintId::of(matches::WILDCARD_IN_OR_PATTERNS), LintId::of(mem_replace::MEM_REPLACE_OPTION_WITH_NONE), @@ -267,6 +266,7 @@ store.register_group(true, "clippy::all", Some("clippy_all"), vec![ LintId::of(option_env_unwrap::OPTION_ENV_UNWRAP), LintId::of(overflow_check_conditional::OVERFLOW_CHECK_CONDITIONAL), LintId::of(partialeq_ne_impl::PARTIALEQ_NE_IMPL), + LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE), LintId::of(precedence::PRECEDENCE), LintId::of(ptr::CMP_NULL), LintId::of(ptr::INVALID_NULL_PTR_USAGE), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs index 9975859c54f..006275d1383 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_correctness.rs @@ -8,7 +8,7 @@ store.register_group(true, "clippy::correctness", Some("clippy_correctness"), ve LintId::of(attrs::DEPRECATED_SEMVER), LintId::of(attrs::MISMATCHED_TARGET_OS), LintId::of(attrs::USELESS_ATTRIBUTE), - LintId::of(booleans::LOGIC_BUG), + LintId::of(booleans::OVERLY_COMPLEX_BOOL_EXPR), LintId::of(casts::CAST_REF_TO_MUT), LintId::of(casts::CAST_SLICE_DIFFERENT_SIZES), LintId::of(copies::IFS_SAME_COND), 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 99bde35cf15..c540573b802 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_lints.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_lints.rs @@ -55,11 +55,10 @@ store.register_lints(&[ await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE, await_holding_invalid::AWAIT_HOLDING_LOCK, await_holding_invalid::AWAIT_HOLDING_REFCELL_REF, - blacklisted_name::BLACKLISTED_NAME, blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS, bool_assert_comparison::BOOL_ASSERT_COMPARISON, - booleans::LOGIC_BUG, booleans::NONMINIMAL_BOOL, + booleans::OVERLY_COMPLEX_BOOL_EXPR, borrow_as_ptr::BORROW_AS_PTR, borrow_deref_ref::BORROW_DEREF_REF, bytecount::NAIVE_BYTECOUNT, @@ -116,6 +115,7 @@ store.register_lints(&[ derive::EXPL_IMPL_CLONE_ON_COPY, derive::UNSAFE_DERIVE_DESERIALIZE, disallowed_methods::DISALLOWED_METHODS, + disallowed_names::DISALLOWED_NAMES, disallowed_script_idents::DISALLOWED_SCRIPT_IDENTS, disallowed_types::DISALLOWED_TYPES, doc::DOC_MARKDOWN, @@ -244,6 +244,7 @@ store.register_lints(&[ manual_assert::MANUAL_ASSERT, manual_async_fn::MANUAL_ASYNC_FN, manual_bits::MANUAL_BITS, + manual_instant_elapsed::MANUAL_INSTANT_ELAPSED, manual_non_exhaustive::MANUAL_NON_EXHAUSTIVE, manual_ok_or::MANUAL_OK_OR, manual_rem_euclid::MANUAL_REM_EUCLID, @@ -453,6 +454,7 @@ store.register_lints(&[ panic_unimplemented::UNIMPLEMENTED, panic_unimplemented::UNREACHABLE, partialeq_ne_impl::PARTIALEQ_NE_IMPL, + partialeq_to_none::PARTIALEQ_TO_NONE, pass_by_ref_or_value::LARGE_TYPES_PASSED_BY_VALUE, pass_by_ref_or_value::TRIVIALLY_COPY_PASS_BY_REF, path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE, diff --git a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs index 642d629971d..91210b23afe 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_nursery.rs @@ -13,6 +13,7 @@ store.register_group(true, "clippy::nursery", Some("clippy_nursery"), vec![ LintId::of(future_not_send::FUTURE_NOT_SEND), LintId::of(index_refutable_slice::INDEX_REFUTABLE_SLICE), LintId::of(let_if_seq::USELESS_LET_IF_SEQ), + LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), LintId::of(methods::ITER_WITH_DRAIN), LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs index a1b54665814..bd7d1a15ab4 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_pedantic.rs @@ -49,6 +49,7 @@ store.register_group(true, "clippy::pedantic", Some("clippy_pedantic"), vec![ LintId::of(loops::EXPLICIT_ITER_LOOP), LintId::of(macro_use::MACRO_USE_IMPORTS), LintId::of(manual_assert::MANUAL_ASSERT), + LintId::of(manual_instant_elapsed::MANUAL_INSTANT_ELAPSED), LintId::of(manual_ok_or::MANUAL_OK_OR), LintId::of(matches::MATCH_BOOL), LintId::of(matches::MATCH_ON_VEC_ITEMS), 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 e95bab1d045..bfa654238f1 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_style.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_style.rs @@ -4,7 +4,6 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(assertions_on_constants::ASSERTIONS_ON_CONSTANTS), - LintId::of(blacklisted_name::BLACKLISTED_NAME), LintId::of(blocks_in_if_conditions::BLOCKS_IN_IF_CONDITIONS), LintId::of(bool_assert_comparison::BOOL_ASSERT_COMPARISON), LintId::of(casts::FN_TO_NUMERIC_CAST), @@ -17,6 +16,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(dereference::NEEDLESS_BORROW), LintId::of(derive::DERIVE_PARTIAL_EQ_WITHOUT_EQ), LintId::of(disallowed_methods::DISALLOWED_METHODS), + LintId::of(disallowed_names::DISALLOWED_NAMES), LintId::of(disallowed_types::DISALLOWED_TYPES), LintId::of(doc::MISSING_SAFETY_DOC), LintId::of(doc::NEEDLESS_DOCTEST_MAIN), @@ -100,6 +100,7 @@ store.register_group(true, "clippy::style", Some("clippy_style"), vec![ LintId::of(operators::ASSIGN_OP_PATTERN), LintId::of(operators::OP_REF), LintId::of(operators::PTR_EQ), + LintId::of(partialeq_to_none::PARTIALEQ_TO_NONE), LintId::of(ptr::CMP_NULL), LintId::of(ptr::PTR_ARG), LintId::of(question_mark::QUESTION_MARK), diff --git a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs index f7558f87098..964992bd94f 100644 --- a/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs +++ b/src/tools/clippy/clippy_lints/src/lib.register_suspicious.rs @@ -22,7 +22,6 @@ store.register_group(true, "clippy::suspicious", Some("clippy_suspicious"), vec! LintId::of(loops::EMPTY_LOOP), LintId::of(loops::FOR_LOOPS_OVER_FALLIBLES), LintId::of(loops::MUT_RANGE_BOUND), - LintId::of(matches::SIGNIFICANT_DROP_IN_SCRUTINEE), LintId::of(methods::NO_EFFECT_REPLACE), LintId::of(methods::SUSPICIOUS_MAP), LintId::of(mut_key::MUTABLE_KEY_TYPE), diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index eb3841272b1..2975399a8bb 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -178,7 +178,6 @@ mod assertions_on_result_states; mod async_yields_async; mod attrs; mod await_holding_invalid; -mod blacklisted_name; mod blocks_in_if_conditions; mod bool_assert_comparison; mod booleans; @@ -206,6 +205,7 @@ mod dereference; mod derivable_impls; mod derive; mod disallowed_methods; +mod disallowed_names; mod disallowed_script_idents; mod disallowed_types; mod doc; @@ -274,6 +274,7 @@ mod main_recursion; mod manual_assert; mod manual_async_fn; mod manual_bits; +mod manual_instant_elapsed; mod manual_non_exhaustive; mod manual_ok_or; mod manual_rem_euclid; @@ -332,6 +333,7 @@ mod overflow_check_conditional; mod panic_in_result_fn; mod panic_unimplemented; mod partialeq_ne_impl; +mod partialeq_to_none; mod pass_by_ref_or_value; mod path_buf_push_overwrite; mod pattern_type_mismatch; @@ -487,7 +489,7 @@ pub fn read_conf(sess: &Session) -> Conf { }, }; - let TryConf { conf, errors } = utils::conf::read(&file_name); + let TryConf { conf, errors, warnings } = utils::conf::read(&file_name); // all conf errors are non-fatal, we just use the default conf in case of error for error in errors { sess.err(&format!( @@ -497,6 +499,15 @@ pub fn read_conf(sess: &Session) -> Conf { )); } + for warning in warnings { + sess.struct_warn(&format!( + "error reading Clippy's configuration file `{}`: {}", + file_name.display(), + format_error(warning) + )) + .emit(); + } + conf } @@ -675,8 +686,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|| Box::new(swap::Swap)); store.register_late_pass(|| Box::new(overflow_check_conditional::OverflowCheckConditional)); store.register_late_pass(|| Box::new(new_without_default::NewWithoutDefault::default())); - let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>(); - store.register_late_pass(move || Box::new(blacklisted_name::BlacklistedName::new(blacklisted_names.clone()))); + let disallowed_names = conf.disallowed_names.iter().cloned().collect::<FxHashSet<_>>(); + store.register_late_pass(move || Box::new(disallowed_names::DisallowedNames::new(disallowed_names.clone()))); let too_many_arguments_threshold = conf.too_many_arguments_threshold; let too_many_lines_threshold = conf.too_many_lines_threshold; store.register_late_pass(move || { @@ -921,6 +932,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(move || Box::new(operators::Operators::new(verbose_bit_mask_threshold))); store.register_late_pass(|| Box::new(invalid_utf8_in_unchecked::InvalidUtf8InUnchecked)); store.register_late_pass(|| Box::new(std_instead_of_core::StdReexports::default())); + store.register_late_pass(|| Box::new(manual_instant_elapsed::ManualInstantElapsed)); + store.register_late_pass(|| Box::new(partialeq_to_none::PartialeqToNone)); // 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 b31015d195b..a65df48e413 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -119,11 +119,9 @@ fn build_manual_memcpy_suggestion<'tcx>( let print_limit = |end: &Expr<'_>, end_str: &str, base: &Expr<'_>, sugg: MinifyingSugg<'static>| { if_chain! { - if let ExprKind::MethodCall(method, len_args, _) = end.kind; + if let ExprKind::MethodCall(method, [recv], _) = end.kind; if method.ident.name == sym::len; - if len_args.len() == 1; - if let Some(arg) = len_args.get(0); - if path_to_local(arg) == path_to_local(base); + if path_to_local(recv) == path_to_local(base); then { if sugg.to_string() == end_str { sugg::EMPTY.into() @@ -343,10 +341,8 @@ fn get_slice_like_element_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Opti fn fetch_cloned_expr<'tcx>(expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { if_chain! { - if let ExprKind::MethodCall(method, args, _) = expr.kind; + if let ExprKind::MethodCall(method, [arg], _) = expr.kind; if method.ident.name == sym::clone; - if args.len() == 1; - if let Some(arg) = args.get(0); then { arg } else { expr } } } diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index a7ef562b21f..7ca4a7c4ebf 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -188,10 +188,9 @@ pub(super) fn check<'tcx>( fn is_len_call(expr: &Expr<'_>, var: Symbol) -> bool { if_chain! { - if let ExprKind::MethodCall(method, len_args, _) = expr.kind; - if len_args.len() == 1; + if let ExprKind::MethodCall(method, [recv], _) = expr.kind; if method.ident.name == sym::len; - if let ExprKind::Path(QPath::Resolved(_, path)) = len_args[0].kind; + if let ExprKind::Path(QPath::Resolved(_, path)) = recv.kind; if path.segments.len() == 1; if path.segments[0].ident.name == var; then { diff --git a/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs b/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs new file mode 100644 index 00000000000..331cda1db89 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/manual_instant_elapsed.rs @@ -0,0 +1,69 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::source_map::Spanned; + +declare_clippy_lint! { + /// ### What it does + /// Lints subtraction between `Instant::now()` and another `Instant`. + /// + /// ### Why is this bad? + /// It is easy to accidentally write `prev_instant - Instant::now()`, which will always be 0ns + /// as `Instant` subtraction saturates. + /// + /// `prev_instant.elapsed()` also more clearly signals intention. + /// + /// ### Example + /// ```rust + /// use std::time::Instant; + /// let prev_instant = Instant::now(); + /// let duration = Instant::now() - prev_instant; + /// ``` + /// Use instead: + /// ```rust + /// use std::time::Instant; + /// let prev_instant = Instant::now(); + /// let duration = prev_instant.elapsed(); + /// ``` + #[clippy::version = "1.64.0"] + pub MANUAL_INSTANT_ELAPSED, + pedantic, + "subtraction between `Instant::now()` and previous `Instant`" +} + +declare_lint_pass!(ManualInstantElapsed => [MANUAL_INSTANT_ELAPSED]); + +impl LateLintPass<'_> for ManualInstantElapsed { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { + if let ExprKind::Binary(Spanned {node: BinOpKind::Sub, ..}, lhs, rhs) = expr.kind + && check_instant_now_call(cx, lhs) + && let ty_resolved = cx.typeck_results().expr_ty(rhs) + && let rustc_middle::ty::Adt(def, _) = ty_resolved.kind() + && clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT) + && let Some(sugg) = clippy_utils::sugg::Sugg::hir_opt(cx, rhs) + { + span_lint_and_sugg( + cx, + MANUAL_INSTANT_ELAPSED, + expr.span, + "manual implementation of `Instant::elapsed`", + "try", + format!("{}.elapsed()", sugg.maybe_par()), + Applicability::MachineApplicable, + ); + } + } +} + +fn check_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool { + if let ExprKind::Call(fn_expr, []) = expr_block.kind + && let Some(fn_id) = clippy_utils::path_def_id(cx, fn_expr) + && clippy_utils::match_def_path(cx, fn_id, &clippy_utils::paths::INSTANT_NOW) + { + true + } else { + false + } +} diff --git a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs index 9abf2507b92..cf5004399b8 100644 --- a/src/tools/clippy/clippy_lints/src/manual_ok_or.rs +++ b/src/tools/clippy/clippy_lints/src/manual_ok_or.rs @@ -47,17 +47,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualOkOr { } if_chain! { - if let ExprKind::MethodCall(method_segment, args, _) = scrutinee.kind; + if let ExprKind::MethodCall(method_segment, [receiver, or_expr, map_expr], _) = scrutinee.kind; if method_segment.ident.name == sym!(map_or); - if args.len() == 3; - let method_receiver = &args[0]; - let ty = cx.typeck_results().expr_ty(method_receiver); + let ty = cx.typeck_results().expr_ty(receiver); if is_type_diagnostic_item(cx, ty, sym::Option); - let or_expr = &args[1]; - if is_ok_wrapping(cx, &args[2]); + if is_ok_wrapping(cx, map_expr); if let ExprKind::Call(Expr { kind: ExprKind::Path(err_path), .. }, &[ref err_arg]) = or_expr.kind; if is_lang_ctor(cx, err_path, ResultErr); - if let Some(method_receiver_snippet) = snippet_opt(cx, method_receiver.span); + if let Some(method_receiver_snippet) = snippet_opt(cx, receiver.span); if let Some(err_arg_snippet) = snippet_opt(cx, err_arg.span); if let Some(indent) = indent_of(cx, scrutinee.span); then { diff --git a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs index 21d0e19eb0a..1e542447c96 100644 --- a/src/tools/clippy/clippy_lints/src/map_err_ignore.rs +++ b/src/tools/clippy/clippy_lints/src/map_err_ignore.rs @@ -113,10 +113,10 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { } // check if this is a method call (e.g. x.foo()) - if let ExprKind::MethodCall(method, args, _) = e.kind { + if let ExprKind::MethodCall(method, [_, arg], _) = e.kind { // only work if the method name is `map_err` and there are only 2 arguments (e.g. x.map_err(|_|[1] // Enum::Variant[2])) - if method.ident.as_str() == "map_err" && args.len() == 2 { + if method.ident.name == sym!(map_err) { // make sure the first argument is a closure, and grab the CaptureRef, BodyId, and fn_decl_span // fields if let ExprKind::Closure(&Closure { @@ -124,7 +124,7 @@ impl<'tcx> LateLintPass<'tcx> for MapErrIgnore { body, fn_decl_span, .. - }) = args[1].kind + }) = arg.kind { // check if this is by Reference (meaning there's no move statement) if capture_clause == CaptureBy::Ref { diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs index af9d948af00..6db852c3ffe 100644 --- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs +++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs @@ -97,11 +97,7 @@ declare_clippy_lint! { declare_lint_pass!(MapUnit => [OPTION_MAP_UNIT_FN, RESULT_MAP_UNIT_FN]); fn is_unit_type(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Tuple(slice) => slice.is_empty(), - ty::Never => true, - _ => false, - } + ty.is_unit() || ty.is_never() } fn is_unit_function(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs index d914eba0171..a0efdecec67 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs @@ -72,10 +72,10 @@ fn is_ref_some_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> Option<BindingAnnotat if is_lang_ctor(cx, qpath, LangItem::OptionSome); if let PatKind::Binding(rb, .., ident, _) = first_pat.kind; if rb == BindingAnnotation::Ref || rb == BindingAnnotation::RefMut; - if let ExprKind::Call(e, args) = peel_blocks(arm.body).kind; + if let ExprKind::Call(e, [arg]) = peel_blocks(arm.body).kind; if let ExprKind::Path(ref some_path) = e.kind; - if is_lang_ctor(cx, some_path, LangItem::OptionSome) && args.len() == 1; - if let ExprKind::Path(QPath::Resolved(_, path2)) = args[0].kind; + if is_lang_ctor(cx, some_path, LangItem::OptionSome); + if let ExprKind::Path(QPath::Resolved(_, path2)) = arg.kind; if path2.segments.len() == 1 && ident.name == path2.segments[0].ident.name; then { return Some(rb) diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index e9e13aece18..e6b183fc05f 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -21,8 +21,8 @@ mod single_match; mod try_err; mod wild_in_or_pats; -use clippy_utils::source::{snippet_opt, span_starts_with, walk_span_to_context}; -use clippy_utils::{higher, in_constant, meets_msrv, msrvs}; +use clippy_utils::source::{snippet_opt, walk_span_to_context}; +use clippy_utils::{higher, in_constant, is_span_match, meets_msrv, msrvs}; use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; @@ -835,7 +835,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.60.0"] pub SIGNIFICANT_DROP_IN_SCRUTINEE, - suspicious, + nursery, "warns when a temporary of a type with a drop with a significant side-effect might have a surprising lifetime" } @@ -949,7 +949,7 @@ impl<'tcx> LateLintPass<'tcx> for Matches { let from_expansion = expr.span.from_expansion(); if let ExprKind::Match(ex, arms, source) = expr.kind { - if source == MatchSource::Normal && !span_starts_with(cx, expr.span, "match") { + if source == MatchSource::Normal && !is_span_match(cx, expr.span) { return; } if matches!(source, MatchSource::Normal | MatchSource::ForLoopDesugar) { diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs index 0491a0679f3..663277d1136 100644 --- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs +++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs @@ -23,12 +23,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine // val, // }; if_chain! { - if let ExprKind::Call(match_fun, try_args) = scrutinee.kind; + if let ExprKind::Call(match_fun, [try_arg, ..]) = scrutinee.kind; if let ExprKind::Path(ref match_fun_path) = match_fun.kind; if matches!(match_fun_path, QPath::LangItem(LangItem::TryTraitBranch, ..)); - if let Some(try_arg) = try_args.get(0); - if let ExprKind::Call(err_fun, err_args) = try_arg.kind; - if let Some(err_arg) = err_args.get(0); + if let ExprKind::Call(err_fun, [err_arg, ..]) = try_arg.kind; if let ExprKind::Path(ref err_fun_path) = err_fun.kind; if is_lang_ctor(cx, err_fun_path, ResultErr); if let Some(return_ty) = find_return_type(cx, &expr.kind); diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs index 41073d40f3d..cad3ea2a176 100644 --- a/src/tools/clippy/clippy_lints/src/mem_replace.rs +++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs @@ -163,8 +163,7 @@ fn check_replace_with_uninit(cx: &LateContext<'_>, src: &Expr<'_>, dest: &Expr<' } if_chain! { - if let ExprKind::Call(repl_func, repl_args) = src.kind; - if repl_args.is_empty(); + if let ExprKind::Call(repl_func, []) = src.kind; 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(); then { @@ -246,11 +245,10 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { // Check that `expr` is a call to `mem::replace()` - if let ExprKind::Call(func, func_args) = expr.kind; + if let ExprKind::Call(func, [dest, src]) = expr.kind; if let ExprKind::Path(ref func_qpath) = func.kind; if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id(); if cx.tcx.is_diagnostic_item(sym::mem_replace, def_id); - if let [dest, src] = func_args; then { check_replace_option_with_none(cx, src, dest, expr.span); check_replace_with_uninit(cx, src, dest, expr.span); diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 0b38a07204e..60e1355f9b9 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_context; use clippy_utils::sugg; use clippy_utils::ty::is_copy; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind}; +use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; use rustc_lint::LateContext; use rustc_middle::ty::{self, adjustment::Adjust}; use rustc_span::symbol::{sym, Symbol}; @@ -86,6 +86,11 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, { return; }, + // ? is a Call, makes sure not to rec *x?, but rather (*x)? + ExprKind::Call(hir_callee, _) => matches!( + hir_callee.kind, + ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _)) + ), ExprKind::MethodCall(_, [self_arg, ..], _) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar | MatchSource::AwaitDesugar) | ExprKind::Field(..) diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs index fbc3348f185..5ef08ca6290 100644 --- a/src/tools/clippy/clippy_lints/src/methods/expect_used.rs +++ b/src/tools/clippy/clippy_lints/src/methods/expect_used.rs @@ -12,9 +12,9 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { - Some((EXPECT_USED, "an Option", "None")) + Some((EXPECT_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((EXPECT_USED, "a Result", "Err")) + Some((EXPECT_USED, "a Result", "Err", "an ")) } else { None }; @@ -23,14 +23,14 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr return; } - if let Some((lint, kind, none_value)) = mess { + if let Some((lint, kind, none_value, none_prefix)) = mess { span_lint_and_help( cx, lint, expr.span, - &format!("used `expect()` on `{}` value", kind,), + &format!("used `expect()` on `{kind}` value"), None, - &format!("if this value is an `{}`, it will panic", none_value,), + &format!("if this value is {none_prefix}`{none_value}`, it will panic"), ); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 202fbc1f7f6..5ac6b09f0aa 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -204,6 +204,17 @@ declare_clippy_lint! { /// option.expect("more helpful message"); /// result.expect("more helpful message"); /// ``` + /// + /// If [expect_used](#expect_used) is enabled, instead: + /// ```rust,ignore + /// # let option = Some(1); + /// # let result: Result<usize, ()> = Ok(1); + /// option?; + /// + /// // or + /// + /// result?; + /// ``` #[clippy::version = "1.45.0"] pub UNWRAP_USED, restriction, diff --git a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs index 5c761014927..ce1a52e5480 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unwrap_used.rs @@ -1,20 +1,20 @@ use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::is_in_test_function; use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_in_test_function, is_lint_allowed}; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::sym; -use super::UNWRAP_USED; +use super::{EXPECT_USED, UNWRAP_USED}; /// lint use of `unwrap()` for `Option`s and `Result`s pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, allow_unwrap_in_tests: bool) { let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs(); let mess = if is_type_diagnostic_item(cx, obj_ty, sym::Option) { - Some((UNWRAP_USED, "an Option", "None")) + Some((UNWRAP_USED, "an Option", "None", "")) } else if is_type_diagnostic_item(cx, obj_ty, sym::Result) { - Some((UNWRAP_USED, "a Result", "Err")) + Some((UNWRAP_USED, "a Result", "Err", "an ")) } else { None }; @@ -23,18 +23,23 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr return; } - if let Some((lint, kind, none_value)) = mess { + if let Some((lint, kind, none_value, none_prefix)) = mess { + let help = if is_lint_allowed(cx, EXPECT_USED, expr.hir_id) { + format!( + "if you don't want to handle the `{none_value}` case gracefully, consider \ + using `expect()` to provide a better panic message" + ) + } else { + format!("if this value is {none_prefix}`{none_value}`, it will panic") + }; + span_lint_and_help( cx, lint, expr.span, - &format!("used `unwrap()` on `{}` value", kind,), + &format!("used `unwrap()` on `{kind}` value"), None, - &format!( - "if you don't want to handle the `{}` case gracefully, consider \ - using `expect()` to provide a better panic message", - none_value, - ), + &help, ); } } diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 16d65966c10..bc304c081b9 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -1,7 +1,9 @@ use clippy_utils::diagnostics::span_lint; use clippy_utils::qualify_min_const_fn::is_min_const_fn; use clippy_utils::ty::has_drop; -use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, meets_msrv, msrvs, trait_ref_of_method}; +use clippy_utils::{ + fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, meets_msrv, msrvs, trait_ref_of_method, +}; use rustc_hir as hir; use rustc_hir::def_id::CRATE_DEF_ID; use rustc_hir::intravisit::FnKind; @@ -86,10 +88,10 @@ impl MissingConstForFn { impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { fn check_fn( &mut self, - cx: &LateContext<'_>, - kind: FnKind<'_>, + cx: &LateContext<'tcx>, + kind: FnKind<'tcx>, _: &FnDecl<'_>, - _: &Body<'_>, + body: &Body<'tcx>, span: Span, hir_id: HirId, ) { @@ -124,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { FnKind::Method(_, sig, ..) => { if trait_ref_of_method(cx, def_id).is_some() || already_const(sig.header) - || method_accepts_dropable(cx, sig.decl.inputs) + || method_accepts_droppable(cx, sig.decl.inputs) { return; } @@ -144,6 +146,10 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { } } + if is_from_proc_macro(cx, &(&kind, body, hir_id, span)) { + return; + } + let mir = cx.tcx.optimized_mir(def_id); if let Err((span, err)) = is_min_const_fn(cx.tcx, mir, self.msrv) { @@ -159,7 +165,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { /// Returns true if any of the method parameters is a type that implements `Drop`. The method /// can't be made const then, because `drop` can't be const-evaluated. -fn method_accepts_dropable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool { +fn method_accepts_droppable(cx: &LateContext<'_>, param_tys: &[hir::Ty<'_>]) -> bool { // If any of the params are droppable, return true param_tys.iter().any(|hir_ty| { let ty_ty = hir_ty_to_ty(cx.tcx, hir_ty); diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index 88ba002927a..3701fdb4adb 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -7,7 +7,8 @@ use clippy_utils::attrs::is_doc_hidden; use clippy_utils::diagnostics::span_lint; -use rustc_ast::ast; +use clippy_utils::is_from_proc_macro; +use rustc_ast::ast::{self, MetaItem, MetaItemKind}; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty::DefIdTree; @@ -57,6 +58,20 @@ impl MissingDoc { *self.doc_hidden_stack.last().expect("empty doc_hidden_stack") } + fn has_include(meta: Option<MetaItem>) -> bool { + if_chain! { + if let Some(meta) = meta; + if let MetaItemKind::List(list) = meta.kind; + if let Some(meta) = list.get(0); + if let Some(name) = meta.ident(); + then { + name.name == sym::include + } else { + false + } + } + } + fn check_missing_docs_attrs( &self, cx: &LateContext<'_>, @@ -80,7 +95,9 @@ impl MissingDoc { return; } - let has_doc = attrs.iter().any(|a| a.doc_str().is_some()); + let has_doc = attrs + .iter() + .any(|a| a.doc_str().is_some() || Self::has_include(a.meta())); if !has_doc { span_lint( cx, @@ -141,14 +158,18 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { let (article, desc) = cx.tcx.article_and_description(it.def_id.to_def_id()); let attrs = cx.tcx.hir().attrs(it.hir_id()); - self.check_missing_docs_attrs(cx, attrs, it.span, article, desc); + if !is_from_proc_macro(cx, it) { + self.check_missing_docs_attrs(cx, attrs, it.span, article, desc); + } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx hir::TraitItem<'_>) { let (article, desc) = cx.tcx.article_and_description(trait_item.def_id.to_def_id()); let attrs = cx.tcx.hir().attrs(trait_item.hir_id()); - self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc); + if !is_from_proc_macro(cx, trait_item) { + self.check_missing_docs_attrs(cx, attrs, trait_item.span, article, desc); + } } fn check_impl_item(&mut self, cx: &LateContext<'tcx>, impl_item: &'tcx hir::ImplItem<'_>) { @@ -163,18 +184,24 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { let (article, desc) = cx.tcx.article_and_description(impl_item.def_id.to_def_id()); let attrs = cx.tcx.hir().attrs(impl_item.hir_id()); - self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc); + if !is_from_proc_macro(cx, impl_item) { + self.check_missing_docs_attrs(cx, attrs, impl_item.span, article, desc); + } } fn check_field_def(&mut self, cx: &LateContext<'tcx>, sf: &'tcx hir::FieldDef<'_>) { if !sf.is_positional() { let attrs = cx.tcx.hir().attrs(sf.hir_id); - self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field"); + if !is_from_proc_macro(cx, sf) { + self.check_missing_docs_attrs(cx, attrs, sf.span, "a", "struct field"); + } } } fn check_variant(&mut self, cx: &LateContext<'tcx>, v: &'tcx hir::Variant<'_>) { let attrs = cx.tcx.hir().attrs(v.id); - self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant"); + if !is_from_proc_macro(cx, v) { + self.check_missing_docs_attrs(cx, attrs, v.span, "a", "variant"); + } } } diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs index 3f5286ba097..d9ee031c9f9 100644 --- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs @@ -37,9 +37,9 @@ declare_lint_pass!(OptionEnvUnwrap => [OPTION_ENV_UNWRAP]); impl EarlyLintPass for OptionEnvUnwrap { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) { if_chain! { - if let ExprKind::MethodCall(path_segment, args, _) = &expr.kind; + if let ExprKind::MethodCall(path_segment, receiver, _, _) = &expr.kind; if matches!(path_segment.ident.name, sym::expect | sym::unwrap); - if let ExprKind::Call(caller, _) = &args[0].kind; + if let ExprKind::Call(caller, _) = &receiver.kind; if is_direct_expn_of(caller.span, "option_env").is_some(); then { span_lint_and_help( diff --git a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs new file mode 100644 index 00000000000..eee7642068d --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs @@ -0,0 +1,104 @@ +use clippy_utils::{ + diagnostics::span_lint_and_sugg, is_lang_ctor, peel_hir_expr_refs, peel_ref_operators, sugg, + ty::is_type_diagnostic_item, +}; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind, LangItem}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::sym; + +declare_clippy_lint! { + /// ### What it does + /// + /// Checks for binary comparisons to a literal `Option::None`. + /// + /// ### Why is this bad? + /// + /// A programmer checking if some `foo` is `None` via a comparison `foo == None` + /// is usually inspired from other programming languages (e.g. `foo is None` + /// in Python). + /// Checking if a value of type `Option<T>` is (not) equal to `None` in that + /// way relies on `T: PartialEq` to do the comparison, which is unneeded. + /// + /// ### Example + /// ```rust + /// fn foo(f: Option<u32>) -> &'static str { + /// if f != None { "yay" } else { "nay" } + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn foo(f: Option<u32>) -> &'static str { + /// if f.is_some() { "yay" } else { "nay" } + /// } + /// ``` + #[clippy::version = "1.64.0"] + pub PARTIALEQ_TO_NONE, + style, + "Binary comparison to `Option<T>::None` relies on `T: PartialEq`, which is unneeded" +} +declare_lint_pass!(PartialeqToNone => [PARTIALEQ_TO_NONE]); + +impl<'tcx> LateLintPass<'tcx> for PartialeqToNone { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { + // Skip expanded code, as we have no control over it anyway... + if e.span.from_expansion() { + return; + } + + // If the expression is of type `Option` + let is_ty_option = + |expr: &Expr<'_>| is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr).peel_refs(), sym::Option); + + // If the expression is a literal `Option::None` + let is_none_ctor = |expr: &Expr<'_>| { + matches!(&peel_hir_expr_refs(expr).0.kind, + ExprKind::Path(p) if is_lang_ctor(cx, p, LangItem::OptionNone)) + }; + + let mut applicability = Applicability::MachineApplicable; + + if let ExprKind::Binary(op, left_side, right_side) = e.kind { + // All other comparisons (e.g. `>= None`) have special meaning wrt T + let is_eq = match op.node { + BinOpKind::Eq => true, + BinOpKind::Ne => false, + _ => return, + }; + + // We are only interested in comparisons between `Option` and a literal `Option::None` + let scrutinee = match ( + is_none_ctor(left_side) && is_ty_option(right_side), + is_none_ctor(right_side) && is_ty_option(left_side), + ) { + (true, false) => right_side, + (false, true) => left_side, + _ => return, + }; + + // Peel away refs/derefs (as long as we don't cross manual deref impls), as + // autoref/autoderef will take care of those + let sugg = format!( + "{}.{}", + sugg::Sugg::hir_with_applicability(cx, peel_ref_operators(cx, scrutinee), "..", &mut applicability) + .maybe_par(), + if is_eq { "is_none()" } else { "is_some()" } + ); + + span_lint_and_sugg( + cx, + PARTIALEQ_TO_NONE, + e.span, + "binary comparison to literal `Option::None`", + if is_eq { + "use `Option::is_none()` instead" + } else { + "use `Option::is_some()` instead" + }, + sugg, + applicability, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs index 3f940ce61c0..bc6a918f703 100644 --- a/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs +++ b/src/tools/clippy/clippy_lints/src/path_buf_push_overwrite.rs @@ -46,11 +46,9 @@ declare_lint_pass!(PathBufPushOverwrite => [PATH_BUF_PUSH_OVERWRITE]); impl<'tcx> LateLintPass<'tcx> for PathBufPushOverwrite { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::MethodCall(path, args, _) = expr.kind; + if let ExprKind::MethodCall(path, [recv, get_index_arg], _) = expr.kind; if path.ident.name == sym!(push); - if args.len() == 2; - if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&args[0]).peel_refs(), sym::PathBuf); - if let Some(get_index_arg) = args.get(1); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv).peel_refs(), sym::PathBuf); if let ExprKind::Lit(ref lit) = get_index_arg.kind; if let LitKind::Str(ref path_lit, _) = lit.node; if let pushed_path = Path::new(path_lit.as_str()); diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs index cc0533c9f5d..e6e3ad05ad7 100644 --- a/src/tools/clippy/clippy_lints/src/precedence.rs +++ b/src/tools/clippy/clippy_lints/src/precedence.rs @@ -109,12 +109,12 @@ impl EarlyLintPass for Precedence { let mut arg = operand; let mut all_odd = true; - while let ExprKind::MethodCall(path_segment, args, _) = &arg.kind { + while let ExprKind::MethodCall(path_segment, receiver, _, _) = &arg.kind { let path_segment_str = path_segment.ident.name.as_str(); all_odd &= ALLOWED_ODD_FUNCTIONS .iter() .any(|odd_function| **odd_function == *path_segment_str); - arg = args.first().expect("A method always has a receiver."); + arg = receiver; } if_chain! { diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index fd0a53839e6..964a057f00d 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -86,8 +86,7 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex if_chain! { if let Some(higher::If { cond, then, r#else }) = higher::If::hir(expr); if !is_else_clause(cx.tcx, expr); - if let ExprKind::MethodCall(segment, args, _) = &cond.kind; - if let Some(caller) = args.get(0); + if let ExprKind::MethodCall(segment, [caller, ..], _) = &cond.kind; let caller_ty = cx.typeck_results().expr_ty(caller); let if_block = IfBlockType::IfIs(caller, caller_ty, segment.ident.name, then, r#else); if is_early_return(sym::Option, cx, &if_block) || is_early_return(sym::Result, cx, &if_block); diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 547d4da8187..fbf842c339e 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -385,24 +385,24 @@ fn check_range_zip_with_len(cx: &LateContext<'_>, path: &PathSegment<'_>, args: if path.ident.as_str() == "zip"; if let [iter, zip_arg] = args; // `.iter()` call - if let ExprKind::MethodCall(iter_path, iter_args, _) = iter.kind; + if let ExprKind::MethodCall(iter_path, [iter_caller, ..], _) = iter.kind; if iter_path.ident.name == sym::iter; // range expression in `.zip()` call: `0..x.len()` if let Some(higher::Range { start: Some(start), end: Some(end), .. }) = higher::Range::hir(zip_arg); if is_integer_const(cx, start, 0); // `.len()` call - if let ExprKind::MethodCall(len_path, len_args, _) = end.kind; - if len_path.ident.name == sym::len && len_args.len() == 1; + if let ExprKind::MethodCall(len_path, [len_caller], _) = end.kind; + if len_path.ident.name == sym::len; // `.iter()` and `.len()` called on same `Path` - if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_args[0].kind; - if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_args[0].kind; - if SpanlessEq::new(cx).eq_path_segments(&iter_path.segments, &len_path.segments); + if let ExprKind::Path(QPath::Resolved(_, iter_path)) = iter_caller.kind; + if let ExprKind::Path(QPath::Resolved(_, len_path)) = len_caller.kind; + if SpanlessEq::new(cx).eq_path_segments(iter_path.segments, len_path.segments); then { span_lint(cx, RANGE_ZIP_WITH_LEN, span, &format!("it is more idiomatic to use `{}.iter().enumerate()`", - snippet(cx, iter_args[0].span, "_")) + snippet(cx, iter_caller.span, "_")) ); } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs index f5a93cebab8..74eea6de4bb 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -1,5 +1,5 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; -use clippy_utils::source::snippet_with_applicability; +use clippy_utils::sugg::Sugg; use if_chain::if_chain; use rustc_ast::ast; use rustc_ast::visit as ast_visit; @@ -69,7 +69,7 @@ impl EarlyLintPass for RedundantClosureCall { if_chain! { if let ast::ExprKind::Call(ref paren, _) = expr.kind; if let ast::ExprKind::Paren(ref closure) = paren.kind; - if let ast::ExprKind::Closure(_, _, _, _, ref decl, ref block, _) = closure.kind; + if let ast::ExprKind::Closure(_, _, ref r#async, _, ref decl, ref block, _) = closure.kind; then { let mut visitor = ReturnVisitor::new(); visitor.visit_expr(block); @@ -81,10 +81,19 @@ impl EarlyLintPass for RedundantClosureCall { "try not to call a closure in the expression where it is declared", |diag| { if decl.inputs.is_empty() { - let mut app = Applicability::MachineApplicable; - let hint = - snippet_with_applicability(cx, block.span, "..", &mut app).into_owned(); - diag.span_suggestion(expr.span, "try doing something like", hint, app); + let app = Applicability::MachineApplicable; + let mut hint = Sugg::ast(cx, block, ".."); + + if r#async.is_async() { + // `async x` is a syntax error, so it becomes `async { x }` + if !matches!(block.kind, ast::ExprKind::Block(_, _)) { + hint = hint.blockify(); + } + + hint = hint.asyncify(); + } + + diag.span_suggestion(expr.span, "try doing something like", hint.to_string(), app); } }, ); diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index f9a9b069193..6bcae0da8f4 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -57,21 +57,20 @@ declare_lint_pass!(Regex => [INVALID_REGEX, TRIVIAL_REGEX]); impl<'tcx> LateLintPass<'tcx> for Regex { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { if_chain! { - if let ExprKind::Call(fun, args) = expr.kind; + if let ExprKind::Call(fun, [arg]) = expr.kind; if let ExprKind::Path(ref qpath) = fun.kind; - if args.len() == 1; if let Some(def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); then { if match_def_path(cx, def_id, &paths::REGEX_NEW) || match_def_path(cx, def_id, &paths::REGEX_BUILDER_NEW) { - check_regex(cx, &args[0], true); + check_regex(cx, arg, true); } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_NEW) || match_def_path(cx, def_id, &paths::REGEX_BYTES_BUILDER_NEW) { - check_regex(cx, &args[0], false); + check_regex(cx, arg, false); } else if match_def_path(cx, def_id, &paths::REGEX_SET_NEW) { - check_set(cx, &args[0], true); + check_set(cx, arg, true); } else if match_def_path(cx, def_id, &paths::REGEX_BYTES_SET_NEW) { - check_set(cx, &args[0], false); + check_set(cx, arg, false); } } } diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index ba03ef93721..6bea6dc0773 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -2,6 +2,7 @@ #[rustfmt::skip] pub static RENAMED_LINTS: &[(&str, &str)] = &[ + ("clippy::blacklisted_name", "clippy::disallowed_names"), ("clippy::block_in_if_condition_expr", "clippy::blocks_in_if_conditions"), ("clippy::block_in_if_condition_stmt", "clippy::blocks_in_if_conditions"), ("clippy::box_vec", "clippy::box_collection"), @@ -14,6 +15,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::for_loop_over_result", "clippy::for_loops_over_fallibles"), ("clippy::identity_conversion", "clippy::useless_conversion"), ("clippy::if_let_some_result", "clippy::match_result_ok"), + ("clippy::logic_bug", "clippy::overly_complex_bool_expr"), ("clippy::new_without_default_derive", "clippy::new_without_default"), ("clippy::option_and_then_some", "clippy::bind_instead_of_map"), ("clippy::option_expect_used", "clippy::expect_used"), diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs index 2c8aa17e80d..b59a25e3a40 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -233,15 +233,10 @@ impl<'a, 'tcx> VectorInitializationVisitor<'a, 'tcx> { /// Returns `true` if give expression is `repeat(0).take(...)` fn is_repeat_take(&self, expr: &Expr<'_>) -> bool { if_chain! { - if let ExprKind::MethodCall(take_path, take_args, _) = expr.kind; + if let ExprKind::MethodCall(take_path, [recv, len_arg, ..], _) = expr.kind; if take_path.ident.name == sym!(take); - // Check that take is applied to `repeat(0)` - if let Some(repeat_expr) = take_args.get(0); - if self.is_repeat_zero(repeat_expr); - - if let Some(len_arg) = take_args.get(1); - + if self.is_repeat_zero(recv); then { // Check that len expression is equals to `with_capacity` expression if SpanlessEq::new(self.cx).eq_expr(len_arg, self.vec_alloc.len_expr) { diff --git a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs index a6c685df721..6d54935f81a 100644 --- a/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs +++ b/src/tools/clippy/clippy_lints/src/stable_sort_primitive.rs @@ -97,12 +97,11 @@ struct LintDetection { fn detect_stable_sort_primitive(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<LintDetection> { if_chain! { - if let ExprKind::MethodCall(method_name, args, _) = &expr.kind; - if let Some(slice) = &args.get(0); + if let ExprKind::MethodCall(method_name, [slice, args @ ..], _) = &expr.kind; if let Some(method) = SortingKind::from_stable_name(method_name.ident.name.as_str()); if let Some(slice_type) = is_slice_of_primitives(cx, slice); then { - let args_str = args.iter().skip(1).map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", "); + let args_str = args.iter().map(|arg| Sugg::hir(cx, arg, "..").to_string()).collect::<Vec<String>>().join(", "); Some(LintDetection { slice_name: Sugg::hir(cx, slice, "..").to_string(), method, method_args: args_str, slice_type }) } else { None diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs index fe885990595..5d36f0f5ff8 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -595,7 +595,7 @@ fn ident_difference_expr_with_base_location( | (Unary(_, _), Unary(_, _)) | (Binary(_, _, _), Binary(_, _, _)) | (Tup(_), Tup(_)) - | (MethodCall(_, _, _), MethodCall(_, _, _)) + | (MethodCall(_, _, _, _), MethodCall(_, _, _, _)) | (Call(_, _), Call(_, _)) | (ConstBlock(_), ConstBlock(_)) | (Array(_), Array(_)) diff --git a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs index 6aa86a57c9b..546242ebd9a 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs @@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for UnitTypes { let_unit_value::check(cx, local); } - fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { unit_cmp::check(cx, expr); unit_arg::check(cx, expr); } diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs index 97d92f10e1c..16da2f11b81 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use if_chain::if_chain; use rustc_errors::Applicability; @@ -7,7 +8,7 @@ use rustc_lint::LateContext; use super::{utils, UNIT_ARG}; -pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if expr.span.from_expansion() { return; } @@ -44,7 +45,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { } }) .collect::<Vec<_>>(); - if !args_to_recover.is_empty() { + if !args_to_recover.is_empty() && !is_from_proc_macro(cx, expr) { lint_unit_args(cx, expr, &args_to_recover); } }, diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs index 306afe44148..e1ec357838d 100644 --- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs +++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs @@ -30,11 +30,10 @@ declare_clippy_lint! { declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]); fn is_useless_rounding(expr: &Expr) -> Option<(&str, String)> { - if let ExprKind::MethodCall(name_ident, args, _) = &expr.kind + if let ExprKind::MethodCall(name_ident, receiver, _, _) = &expr.kind && let method_name = name_ident.ident.name.as_str() && (method_name == "ceil" || method_name == "round" || method_name == "floor") - && !args.is_empty() - && let ExprKind::Lit(spanned) = &args[0].kind + && let ExprKind::Lit(spanned) = &receiver.kind && let LitKind::Float(symbol, ty) = spanned.kind { let f = symbol.as_str().parse::<f64>().unwrap(); let f_str = symbol.to_string() + if let LitFloatType::Suffixed(ty) = ty { diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs index 52585e59566..cd1d90e860b 100644 --- a/src/tools/clippy/clippy_lints/src/unused_unit.rs +++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs @@ -89,7 +89,7 @@ impl EarlyLintPass for UnusedUnit { } } - fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef, _: &ast::TraitBoundModifier) { + fn check_poly_trait_ref(&mut self, cx: &EarlyContext<'_>, poly: &ast::PolyTraitRef) { let segments = &poly.trait_ref.path.segments; if_chain! { diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index fe29bf29d0c..b6738e2891d 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -59,17 +59,17 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { ExprKind::Ret(Some(e)) | ExprKind::Break(_, Some(e)) => e, _ => return, }; - if let ExprKind::Call(_, args) = e.kind { - self.try_desugar_arm.push(args[0].hir_id); + if let ExprKind::Call(_, [arg, ..]) = e.kind { + self.try_desugar_arm.push(arg.hir_id); } }, - ExprKind::MethodCall(name, .., args, _) => { + ExprKind::MethodCall(name, .., [recv, ..], _) => { if is_trait_method(cx, e, sym::Into) && name.ident.as_str() == "into" { let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); + let b = cx.typeck_results().expr_ty(recv); if same_type_and_consts(a, b) { - let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string(); + let sugg = snippet_with_macro_callsite(cx, recv.span, "<expr>").to_string(); span_lint_and_sugg( cx, USELESS_CONVERSION, @@ -90,9 +90,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } } let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); + let b = cx.typeck_results().expr_ty(recv); if same_type_and_consts(a, b) { - let sugg = snippet(cx, args[0].span, "<expr>").into_owned(); + let sugg = snippet(cx, recv.span, "<expr>").into_owned(); span_lint_and_sugg( cx, USELESS_CONVERSION, @@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if_chain! { if is_trait_method(cx, e, sym::TryInto) && name.ident.name == sym::try_into; let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); + let b = cx.typeck_results().expr_ty(recv); if is_type_diagnostic_item(cx, a, sym::Result); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); @@ -126,14 +126,13 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } }, - ExprKind::Call(path, args) => { + ExprKind::Call(path, [arg]) => { if_chain! { - if args.len() == 1; if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); then { let a = cx.typeck_results().expr_ty(e); - let b = cx.typeck_results().expr_ty(&args[0]); + let b = cx.typeck_results().expr_ty(arg); if_chain! { if match_def_path(cx, def_id, &paths::TRY_FROM); if is_type_diagnostic_item(cx, a, sym::Result); @@ -159,7 +158,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if same_type_and_consts(a, b); then { - let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par(); + let sugg = Sugg::hir_with_macro_callsite(cx, arg, "<expr>").maybe_par(); let sugg_msg = format!("consider removing `{}()`", snippet(cx, path.span, "From::from")); span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index 6e033b3be2d..3faae9ac0d2 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -30,7 +30,7 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[ "MinGW", "CamelCase", ]; -const DEFAULT_BLACKLISTED_NAMES: &[&str] = &["foo", "baz", "quux"]; +const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"]; /// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint. #[derive(Clone, Debug, Deserialize)] @@ -68,6 +68,7 @@ pub enum DisallowedType { pub struct TryConf { pub conf: Conf, pub errors: Vec<Box<dyn Error>>, + pub warnings: Vec<Box<dyn Error>>, } impl TryConf { @@ -75,6 +76,7 @@ impl TryConf { Self { conf: Conf::default(), errors: vec![Box::new(error)], + warnings: vec![], } } } @@ -90,14 +92,14 @@ impl fmt::Display for ConfError { impl Error for ConfError {} -fn conf_error(s: String) -> Box<dyn Error> { - Box::new(ConfError(s)) +fn conf_error(s: impl Into<String>) -> Box<dyn Error> { + Box::new(ConfError(s.into())) } macro_rules! define_Conf { ($( $(#[doc = $doc:literal])+ - $(#[conf_deprecated($dep:literal)])? + $(#[conf_deprecated($dep:literal, $new_conf:ident)])? ($name:ident: $ty:ty = $default:expr), )*) => { /// Clippy lint configuration @@ -137,17 +139,29 @@ macro_rules! define_Conf { fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error> where V: MapAccess<'de> { let mut errors = Vec::new(); + let mut warnings = Vec::new(); $(let mut $name = None;)* // could get `Field` here directly, but get `str` first for diagnostics while let Some(name) = map.next_key::<&str>()? { match Field::deserialize(name.into_deserializer())? { $(Field::$name => { - $(errors.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)? + $(warnings.push(conf_error(format!("deprecated field `{}`. {}", name, $dep)));)? match map.next_value() { Err(e) => errors.push(conf_error(e.to_string())), Ok(value) => match $name { Some(_) => errors.push(conf_error(format!("duplicate field `{}`", name))), - None => $name = Some(value), + None => { + $name = Some(value); + // $new_conf is the same as one of the defined `$name`s, so + // this variable is defined in line 2 of this function. + $(match $new_conf { + Some(_) => errors.push(conf_error(concat!( + "duplicate field `", stringify!($new_conf), + "` (provided as `", stringify!($name), "`)" + ))), + None => $new_conf = $name.clone(), + })? + }, } } })* @@ -156,7 +170,7 @@ macro_rules! define_Conf { } } let conf = Conf { $($name: $name.unwrap_or_else(defaults::$name),)* }; - Ok(TryConf { conf, errors }) + Ok(TryConf { conf, errors, warnings }) } } @@ -203,12 +217,11 @@ define_Conf! { /// /// The minimum rust version that the project supports (msrv: Option<String> = None), - /// Lint: BLACKLISTED_NAME. + /// DEPRECATED LINT: BLACKLISTED_NAME. /// - /// The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses. The value - /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the - /// default configuration of Clippy. By default any configuraction will replace the default value. - (blacklisted_names: Vec<String> = super::DEFAULT_BLACKLISTED_NAMES.iter().map(ToString::to_string).collect()), + /// Use the Disallowed Names lint instead + #[conf_deprecated("Please use `disallowed-names` instead", disallowed_names)] + (blacklisted_names: Vec<String> = Vec::new()), /// Lint: COGNITIVE_COMPLEXITY. /// /// The maximum cognitive complexity a function can have @@ -216,8 +229,14 @@ define_Conf! { /// DEPRECATED LINT: CYCLOMATIC_COMPLEXITY. /// /// Use the Cognitive Complexity lint instead. - #[conf_deprecated("Please use `cognitive-complexity-threshold` instead")] - (cyclomatic_complexity_threshold: Option<u64> = None), + #[conf_deprecated("Please use `cognitive-complexity-threshold` instead", cognitive_complexity_threshold)] + (cyclomatic_complexity_threshold: u64 = 25), + /// Lint: DISALLOWED_NAMES. + /// + /// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value + /// `".."` can be used as part of the list to indicate, that the configured values should be appended to the + /// default configuration of Clippy. By default any configuration will replace the default value. + (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()), /// Lint: DOC_MARKDOWN. /// /// The list of words this lint should not consider as identifiers needing ticks. The value @@ -420,7 +439,7 @@ pub fn read(path: &Path) -> TryConf { match toml::from_str::<TryConf>(&content) { Ok(mut conf) => { extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS); - extend_vec_if_indicator_present(&mut conf.conf.blacklisted_names, DEFAULT_BLACKLISTED_NAMES); + extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES); conf }, 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 b309653291b..5dcacd604be 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -496,12 +496,14 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass { cx, }; let body_id = cx.tcx.hir().body_owned_by( - impl_item_refs - .iter() - .find(|iiref| iiref.ident.as_str() == "get_lints") - .expect("LintPass needs to implement get_lints") - .id - .hir_id(), + cx.tcx.hir().local_def_id( + impl_item_refs + .iter() + .find(|iiref| iiref.ident.as_str() == "get_lints") + .expect("LintPass needs to implement get_lints") + .id + .hir_id(), + ), ); collector.visit_expr(&cx.tcx.hir().body(body_id).value); } @@ -569,7 +571,7 @@ fn check_invalid_clippy_version_attribute(cx: &LateContext<'_>, item: &'_ Item<' item.span, "this item has an invalid `clippy::version` attribute", None, - "please use a valid sematic version, see `doc/adding_lints.md`", + "please use a valid semantic version, see `doc/adding_lints.md`", ); } } else { diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs index 92934c16d4b..92cf42c7ad4 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs @@ -619,7 +619,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { if_chain! { // item validation if is_lint_ref_type(cx, ty); - // blacklist check + // disallow check let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); // metadata extraction @@ -644,7 +644,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { if_chain! { if is_deprecated_lint(cx, ty); - // blacklist check + // disallow check let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); // Metadata the little we can get from a deprecated lint diff --git a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs index 8e2ddd225fd..afd0077a658 100644 --- a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs +++ b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs @@ -61,10 +61,10 @@ impl<'tcx> LateLintPass<'tcx> for VerboseFileReads { fn is_file_read_to_end<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> bool { if_chain! { - if let ExprKind::MethodCall(method_name, exprs, _) = expr.kind; + if let ExprKind::MethodCall(method_name, [recv, ..], _) = expr.kind; if method_name.ident.as_str() == "read_to_end"; - if let ExprKind::Path(QPath::Resolved(None, _)) = &exprs[0].kind; - let ty = cx.typeck_results().expr_ty(&exprs[0]); + if let ExprKind::Path(QPath::Resolved(None, _)) = &recv.kind; + let ty = cx.typeck_results().expr_ty(recv); if match_type(cx, ty, &paths::FILE); then { return true diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index bb443bdc116..a688050f63a 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.64" +version = "0.1.65" edition = "2021" publish = false diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index b226026323b..9f74729bdfa 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -147,7 +147,9 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Array(l), Array(r)) | (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)), (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value), (Call(lc, la), Call(rc, ra)) => eq_expr(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)), - (MethodCall(lc, la, _), MethodCall(rc, ra, _)) => eq_path_seg(lc, rc) && over(la, ra, |l, r| eq_expr(l, r)), + (MethodCall(lc, ls, la, _), MethodCall(rc, rs, ra, _)) => { + eq_path_seg(lc, rc) && eq_expr(ls, rs) && over(la, ra, |l, r| eq_expr(l, r)) + }, (Binary(lo, ll, lr), Binary(ro, rl, rr)) => lo.node == ro.node && eq_expr(ll, rl) && eq_expr(lr, rr), (Unary(lo, l), Unary(ro, r)) => mem::discriminant(lo) == mem::discriminant(ro) && eq_expr(l, r), (Lit(l), Lit(r)) => l.kind == r.kind, diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs new file mode 100644 index 00000000000..8335ffae81e --- /dev/null +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -0,0 +1,329 @@ +//! This module handles checking if the span given is from a proc-macro or not. +//! +//! Proc-macros are capable of setting the span of every token they output to a few possible spans. +//! This includes spans we can detect easily as coming from a proc-macro (e.g. the call site +//! or the def site), and spans we can't easily detect as such (e.g. the span of any token +//! passed into the proc macro). This capability means proc-macros are capable of generating code +//! with a span that looks like it was written by the user, but which should not be linted by clippy +//! as it was generated by an external macro. +//! +//! That brings us to this module. The current approach is to determine a small bit of text which +//! must exist at both the start and the end of an item (e.g. an expression or a path) assuming the +//! code was written, and check if the span contains that text. Note this will only work correctly +//! if the span is not from a `macro_rules` based macro. + +use rustc_ast::ast::{IntTy, LitIntType, LitKind, StrStyle, UintTy}; +use rustc_hir::{ + intravisit::FnKind, Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId, + Impl, ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, Node, QPath, TraitItem, + TraitItemKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource, +}; +use rustc_lint::{LateContext, LintContext}; +use rustc_middle::ty::TyCtxt; +use rustc_session::Session; +use rustc_span::{Span, Symbol}; +use rustc_target::spec::abi::Abi; + +/// The search pattern to look for. Used by `span_matches_pat` +#[derive(Clone, Copy)] +pub enum Pat { + /// A single string. + Str(&'static str), + /// Any of the given strings. + MultiStr(&'static [&'static str]), + /// The string representation of the symbol. + Sym(Symbol), + /// Any decimal or hexadecimal digit depending on the location. + Num, +} + +/// Checks if the start and the end of the span's text matches the patterns. This will return false +/// if the span crosses multiple files or if source is not available. +fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) -> bool { + let pos = sess.source_map().lookup_byte_offset(span.lo()); + let Some(ref src) = pos.sf.src else { + return false; + }; + let end = span.hi() - pos.sf.start_pos; + src.get(pos.pos.0 as usize..end.0 as usize).map_or(false, |s| { + // Spans can be wrapped in a mixture or parenthesis, whitespace, and trailing commas. + let start_str = s.trim_start_matches(|c: char| c.is_whitespace() || c == '('); + let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ','); + (match start_pat { + Pat::Str(text) => start_str.starts_with(text), + Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)), + Pat::Sym(sym) => start_str.starts_with(sym.as_str()), + Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit), + } && match end_pat { + Pat::Str(text) => end_str.ends_with(text), + Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)), + Pat::Sym(sym) => end_str.ends_with(sym.as_str()), + Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit), + }) + }) +} + +/// Get the search patterns to use for the given literal +fn lit_search_pat(lit: &LitKind) -> (Pat, Pat) { + match lit { + LitKind::Str(_, StrStyle::Cooked) => (Pat::Str("\""), Pat::Str("\"")), + LitKind::Str(_, StrStyle::Raw(0)) => (Pat::Str("r"), Pat::Str("\"")), + LitKind::Str(_, StrStyle::Raw(_)) => (Pat::Str("r#"), Pat::Str("#")), + LitKind::ByteStr(_) => (Pat::Str("b\""), Pat::Str("\"")), + LitKind::Byte(_) => (Pat::Str("b'"), Pat::Str("'")), + LitKind::Char(_) => (Pat::Str("'"), Pat::Str("'")), + LitKind::Int(_, LitIntType::Signed(IntTy::Isize)) => (Pat::Num, Pat::Str("isize")), + LitKind::Int(_, LitIntType::Unsigned(UintTy::Usize)) => (Pat::Num, Pat::Str("usize")), + LitKind::Int(..) => (Pat::Num, Pat::Num), + LitKind::Float(..) => (Pat::Num, Pat::Str("")), + LitKind::Bool(true) => (Pat::Str("true"), Pat::Str("true")), + LitKind::Bool(false) => (Pat::Str("false"), Pat::Str("false")), + _ => (Pat::Str(""), Pat::Str("")), + } +} + +/// Get the search patterns to use for the given path +fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) { + match path { + QPath::Resolved(ty, path) => { + let start = if ty.is_some() { + Pat::Str("<") + } else { + path.segments + .first() + .map_or(Pat::Str(""), |seg| Pat::Sym(seg.ident.name)) + }; + let end = path.segments.last().map_or(Pat::Str(""), |seg| { + if seg.args.is_some() { + Pat::Str(">") + } else { + Pat::Sym(seg.ident.name) + } + }); + (start, end) + }, + QPath::TypeRelative(_, name) => (Pat::Str(""), Pat::Sym(name.ident.name)), + QPath::LangItem(..) => (Pat::Str(""), Pat::Str("")), + } +} + +/// Get the search patterns to use for the given expression +fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { + match e.kind { + ExprKind::Box(e) => (Pat::Str("box"), expr_search_pat(tcx, e).1), + ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")), + ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")), + ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1), + ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1), + ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1), + ExprKind::Lit(ref lit) => lit_search_pat(&lit.node), + ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")), + ExprKind::Call(e, []) | ExprKind::MethodCall(_, [e], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")), + ExprKind::Call(first, [.., last]) + | ExprKind::MethodCall(_, [first, .., last], _) + | ExprKind::Binary(_, first, last) + | ExprKind::Tup([first, .., last]) + | ExprKind::Assign(first, last, _) + | ExprKind::AssignOp(_, first, last) => (expr_search_pat(tcx, first).0, expr_search_pat(tcx, last).1), + ExprKind::Tup([e]) | ExprKind::DropTemps(e) => expr_search_pat(tcx, e), + ExprKind::Cast(e, _) | ExprKind::Type(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("")), + ExprKind::Let(let_expr) => (Pat::Str("let"), expr_search_pat(tcx, let_expr.init).1), + ExprKind::If(..) => (Pat::Str("if"), Pat::Str("}")), + ExprKind::Loop(_, Some(_), _, _) | ExprKind::Block(_, Some(_)) => (Pat::Str("'"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::Loop, _) => (Pat::Str("loop"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::While, _) => (Pat::Str("while"), Pat::Str("}")), + ExprKind::Loop(_, None, LoopSource::ForLoop, _) | ExprKind::Match(_, _, MatchSource::ForLoopDesugar) => { + (Pat::Str("for"), Pat::Str("}")) + }, + ExprKind::Match(_, _, MatchSource::Normal) => (Pat::Str("match"), Pat::Str("}")), + ExprKind::Match(e, _, MatchSource::TryDesugar) => (expr_search_pat(tcx, e).0, Pat::Str("?")), + ExprKind::Match(e, _, MatchSource::AwaitDesugar) | ExprKind::Yield(e, YieldSource::Await { .. }) => { + (expr_search_pat(tcx, e).0, Pat::Str("await")) + }, + ExprKind::Closure(&Closure { body, .. }) => (Pat::Str(""), expr_search_pat(tcx, &tcx.hir().body(body).value).1), + ExprKind::Block( + Block { + rules: BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided), + .. + }, + None, + ) => (Pat::Str("unsafe"), Pat::Str("}")), + ExprKind::Block(_, None) => (Pat::Str("{"), Pat::Str("}")), + ExprKind::Field(e, name) => (expr_search_pat(tcx, e).0, Pat::Sym(name.name)), + ExprKind::Index(e, _) => (expr_search_pat(tcx, e).0, Pat::Str("]")), + ExprKind::Path(ref path) => qpath_search_pat(path), + ExprKind::AddrOf(_, _, e) => (Pat::Str("&"), expr_search_pat(tcx, e).1), + ExprKind::Break(Destination { label: None, .. }, None) => (Pat::Str("break"), Pat::Str("break")), + ExprKind::Break(Destination { label: Some(name), .. }, None) => (Pat::Str("break"), Pat::Sym(name.ident.name)), + ExprKind::Break(_, Some(e)) => (Pat::Str("break"), expr_search_pat(tcx, e).1), + ExprKind::Continue(Destination { label: None, .. }) => (Pat::Str("continue"), Pat::Str("continue")), + ExprKind::Continue(Destination { label: Some(name), .. }) => (Pat::Str("continue"), Pat::Sym(name.ident.name)), + ExprKind::Ret(None) => (Pat::Str("return"), Pat::Str("return")), + ExprKind::Ret(Some(e)) => (Pat::Str("return"), expr_search_pat(tcx, e).1), + ExprKind::Struct(path, _, _) => (qpath_search_pat(path).0, Pat::Str("}")), + ExprKind::Yield(e, YieldSource::Yield) => (Pat::Str("yield"), expr_search_pat(tcx, e).1), + _ => (Pat::Str(""), Pat::Str("")), + } +} + +fn fn_header_search_pat(header: FnHeader) -> Pat { + if header.is_async() { + Pat::Str("async") + } else if header.is_const() { + Pat::Str("const") + } else if header.is_unsafe() { + Pat::Str("unsafe") + } else if header.abi != Abi::Rust { + Pat::Str("extern") + } else { + Pat::MultiStr(&["fn", "extern"]) + } +} + +fn item_search_pat(item: &Item<'_>) -> (Pat, Pat) { + let (start_pat, end_pat) = match &item.kind { + ItemKind::ExternCrate(_) => (Pat::Str("extern"), Pat::Str(";")), + ItemKind::Static(..) => (Pat::Str("static"), Pat::Str(";")), + ItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), + ItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), + ItemKind::ForeignMod { .. } => (Pat::Str("extern"), Pat::Str("}")), + ItemKind::TyAlias(..) | ItemKind::OpaqueTy(_) => (Pat::Str("type"), Pat::Str(";")), + ItemKind::Enum(..) => (Pat::Str("enum"), Pat::Str("}")), + ItemKind::Struct(VariantData::Struct(..), _) => (Pat::Str("struct"), Pat::Str("}")), + ItemKind::Struct(..) => (Pat::Str("struct"), Pat::Str(";")), + ItemKind::Union(..) => (Pat::Str("union"), Pat::Str("}")), + ItemKind::Trait(_, Unsafety::Unsafe, ..) + | ItemKind::Impl(Impl { + unsafety: Unsafety::Unsafe, + .. + }) => (Pat::Str("unsafe"), Pat::Str("}")), + ItemKind::Trait(IsAuto::Yes, ..) => (Pat::Str("auto"), Pat::Str("}")), + ItemKind::Trait(..) => (Pat::Str("trait"), Pat::Str("}")), + ItemKind::Impl(_) => (Pat::Str("impl"), Pat::Str("}")), + _ => return (Pat::Str(""), Pat::Str("")), + }; + if item.vis_span.is_empty() { + (start_pat, end_pat) + } else { + (Pat::Str("pub"), end_pat) + } +} + +fn trait_item_search_pat(item: &TraitItem<'_>) -> (Pat, Pat) { + match &item.kind { + TraitItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), + TraitItemKind::Type(..) => (Pat::Str("type"), Pat::Str(";")), + TraitItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), + } +} + +fn impl_item_search_pat(item: &ImplItem<'_>) -> (Pat, Pat) { + let (start_pat, end_pat) = match &item.kind { + ImplItemKind::Const(..) => (Pat::Str("const"), Pat::Str(";")), + ImplItemKind::TyAlias(..) => (Pat::Str("type"), Pat::Str(";")), + ImplItemKind::Fn(sig, ..) => (fn_header_search_pat(sig.header), Pat::Str("")), + }; + if item.vis_span.is_empty() { + (start_pat, end_pat) + } else { + (Pat::Str("pub"), end_pat) + } +} + +fn field_def_search_pat(def: &FieldDef<'_>) -> (Pat, Pat) { + if def.vis_span.is_empty() { + if def.is_positional() { + (Pat::Str(""), Pat::Str("")) + } else { + (Pat::Sym(def.ident.name), Pat::Str("")) + } + } else { + (Pat::Str("pub"), Pat::Str("")) + } +} + +fn variant_search_pat(v: &Variant<'_>) -> (Pat, Pat) { + match v.data { + VariantData::Struct(..) => (Pat::Sym(v.ident.name), Pat::Str("}")), + VariantData::Tuple(..) => (Pat::Sym(v.ident.name), Pat::Str("")), + VariantData::Unit(..) => (Pat::Sym(v.ident.name), Pat::Sym(v.ident.name)), + } +} + +fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirId) -> (Pat, Pat) { + let (start_pat, end_pat) = match kind { + FnKind::ItemFn(.., header) => (fn_header_search_pat(*header), Pat::Str("")), + FnKind::Method(.., sig) => (fn_header_search_pat(sig.header), Pat::Str("")), + FnKind::Closure => return (Pat::Str(""), expr_search_pat(tcx, &body.value).1), + }; + let start_pat = match tcx.hir().get(hir_id) { + Node::Item(Item { vis_span, .. }) | Node::ImplItem(ImplItem { vis_span, .. }) => { + if vis_span.is_empty() { + start_pat + } else { + Pat::Str("pub") + } + }, + Node::TraitItem(_) => start_pat, + _ => Pat::Str(""), + }; + (start_pat, end_pat) +} + +pub trait WithSearchPat { + type Context: LintContext; + fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat); + fn span(&self) -> Span; +} +macro_rules! impl_with_search_pat { + ($cx:ident: $ty:ident with $fn:ident $(($tcx:ident))?) => { + impl<'cx> WithSearchPat for $ty<'cx> { + type Context = $cx<'cx>; + #[allow(unused_variables)] + fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) { + $(let $tcx = cx.tcx;)? + $fn($($tcx,)? self) + } + fn span(&self) -> Span { + self.span + } + } + }; +} +impl_with_search_pat!(LateContext: Expr with expr_search_pat(tcx)); +impl_with_search_pat!(LateContext: Item with item_search_pat); +impl_with_search_pat!(LateContext: TraitItem with trait_item_search_pat); +impl_with_search_pat!(LateContext: ImplItem with impl_item_search_pat); +impl_with_search_pat!(LateContext: FieldDef with field_def_search_pat); +impl_with_search_pat!(LateContext: Variant with variant_search_pat); + +impl<'cx> WithSearchPat for (&FnKind<'cx>, &Body<'cx>, HirId, Span) { + type Context = LateContext<'cx>; + + fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat) { + fn_kind_pat(cx.tcx, self.0, self.1, self.2) + } + + fn span(&self) -> Span { + self.3 + } +} + +/// Checks if the item likely came from a proc-macro. +/// +/// This should be called after `in_external_macro` and the initial pattern matching of the ast as +/// it is significantly slower than both of those. +pub fn is_from_proc_macro<T: WithSearchPat>(cx: &T::Context, item: &T) -> bool { + let (start_pat, end_pat) = item.search_pat(cx); + !span_matches_pat(cx.sess(), item.span(), start_pat, end_pat) +} + +/// Checks if the span actually refers to a match expression +pub fn is_span_match(cx: &impl LintContext, span: Span) -> bool { + span_matches_pat(cx.sess(), span, Pat::Str("match"), Pat::Str("}")) +} + +/// Checks if the span actually refers to an if expression +pub fn is_span_if(cx: &impl LintContext, span: Span) -> bool { + span_matches_pat(cx.sess(), span, Pat::Str("if"), Pat::Str("}")) +} diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 7493a8685df..2616a578bb8 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -39,6 +39,7 @@ pub mod sym_helper; pub mod ast_utils; pub mod attrs; +mod check_proc_macro; pub mod comparisons; pub mod consts; pub mod diagnostics; @@ -59,6 +60,7 @@ pub mod usage; pub mod visitors; pub use self::attrs::*; +pub use self::check_proc_macro::{is_from_proc_macro, is_span_if, is_span_match}; pub use self::hir_utils::{ both, count_eq, eq_expr_value, hash_expr, hash_stmt, over, HirEqInterExpr, SpanlessEq, SpanlessHash, }; diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs index 3fb5415ce02..80098d9766c 100644 --- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs +++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs @@ -223,10 +223,12 @@ impl<'a> NumericLiteral<'a> { fn split_suffix<'a>(src: &'a str, lit_kind: &LitKind) -> (&'a str, Option<&'a str>) { debug_assert!(lit_kind.is_numeric()); - lit_suffix_length(lit_kind).map_or((src, None), |suffix_length| { - let (unsuffixed, suffix) = src.split_at(src.len() - suffix_length); - (unsuffixed, Some(suffix)) - }) + lit_suffix_length(lit_kind) + .and_then(|suffix_length| src.len().checked_sub(suffix_length)) + .map_or((src, None), |split_pos| { + let (unsuffixed, suffix) = src.split_at(split_pos); + (unsuffixed, Some(suffix)) + }) } fn lit_suffix_length(lit_kind: &LitKind) -> Option<usize> { diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 05429d05d9e..8d697a301c4 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -194,3 +194,5 @@ pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"]; pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"]; pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"]; pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"]; +pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"]; +pub const INSTANT: [&str; 3] = ["std", "time", "Instant"]; diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 1197fe914de..d85f591fb9a 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -11,24 +11,6 @@ use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext}; use std::borrow::Cow; -/// Checks if the span starts with the given text. This will return false if the span crosses -/// multiple files or if source is not available. -/// -/// This is used to check for proc macros giving unhelpful spans to things. -pub fn span_starts_with<T: LintContext>(cx: &T, span: Span, text: &str) -> bool { - fn helper(sm: &SourceMap, span: Span, text: &str) -> bool { - let pos = sm.lookup_byte_offset(span.lo()); - let Some(ref src) = pos.sf.src else { - return false; - }; - let end = span.hi() - pos.sf.start_pos; - src.get(pos.pos.0 as usize..end.0 as usize) - // Expression spans can include wrapping parenthesis. Remove them first. - .map_or(false, |s| s.trim_start_matches('(').starts_with(text)) - } - helper(cx.sess().source_map(), span, text) -} - /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. /// Also takes an `Option<String>` which can be put inside the braces. pub fn expr_block<'a, T: LintContext>( diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index bad291dfc25..081c98e2f3c 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -315,6 +315,12 @@ impl<'a> Sugg<'a> { Sugg::NonParen(Cow::Owned(format!("{{ {} }}", self))) } + /// Convenience method to prefix the expression with the `async` keyword. + /// Can be used after `blockify` to create an async block. + pub fn asyncify(self) -> Sugg<'static> { + Sugg::NonParen(Cow::Owned(format!("async {}", self))) + } + /// Convenience method to create the `<lhs>..<rhs>` or `<lhs>...<rhs>` /// suggestion. pub fn range(self, end: &Self, limit: ast::RangeLimits) -> Sugg<'static> { diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index a05d633d980..e7d670766a0 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -503,7 +503,7 @@ pub fn all_predicates_of(tcx: TyCtxt<'_>, id: DefId) -> impl Iterator<Item = &(P pub enum ExprFnSig<'tcx> { Sig(Binder<'tcx, FnSig<'tcx>>, Option<DefId>), Closure(Option<&'tcx FnDecl<'tcx>>, Binder<'tcx, FnSig<'tcx>>), - Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>), + Trait(Binder<'tcx, Ty<'tcx>>, Option<Binder<'tcx, Ty<'tcx>>>, Option<DefId>), } impl<'tcx> ExprFnSig<'tcx> { /// Gets the argument type at the given offset. This will return `None` when the index is out of @@ -518,7 +518,7 @@ impl<'tcx> ExprFnSig<'tcx> { } }, Self::Closure(_, sig) => Some(sig.input(0).map_bound(|ty| ty.tuple_fields()[i])), - Self::Trait(inputs, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])), + Self::Trait(inputs, _, _) => Some(inputs.map_bound(|ty| ty.tuple_fields()[i])), } } @@ -541,7 +541,7 @@ impl<'tcx> ExprFnSig<'tcx> { decl.and_then(|decl| decl.inputs.get(i)), sig.input(0).map_bound(|ty| ty.tuple_fields()[i]), )), - Self::Trait(inputs, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))), + Self::Trait(inputs, _, _) => Some((None, inputs.map_bound(|ty| ty.tuple_fields()[i]))), } } @@ -550,12 +550,16 @@ impl<'tcx> ExprFnSig<'tcx> { pub fn output(self) -> Option<Binder<'tcx, Ty<'tcx>>> { match self { Self::Sig(sig, _) | Self::Closure(_, sig) => Some(sig.output()), - Self::Trait(_, output) => output, + Self::Trait(_, output, _) => output, } } pub fn predicates_id(&self) -> Option<DefId> { - if let ExprFnSig::Sig(_, id) = *self { id } else { None } + if let ExprFnSig::Sig(_, id) | ExprFnSig::Trait(_, _, id) = *self { + id + } else { + None + } } } @@ -568,7 +572,8 @@ pub fn expr_sig<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>) -> Option<ExprFnS } } -fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> { +/// If the type is function like, get the signature for it. +pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> { if ty.is_box() { return ty_sig(cx, ty.boxed_ty()); } @@ -580,7 +585,7 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> Some(ExprFnSig::Closure(decl, subs.as_closure().sig())) }, ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.bound_fn_sig(id).subst(cx.tcx, subs), Some(id))), - ty::Opaque(id, _) => ty_sig(cx, cx.tcx.type_of(id)), + ty::Opaque(id, _) => sig_from_bounds(cx, ty, cx.tcx.item_bounds(id), cx.tcx.opt_parent(id)), ty::FnPtr(sig) => Some(ExprFnSig::Sig(sig, None)), ty::Dynamic(bounds, _) => { let lang_items = cx.tcx.lang_items(); @@ -594,26 +599,31 @@ fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> .projection_bounds() .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id())) .map(|p| p.map_bound(|p| p.term.ty().unwrap())); - Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output)) + Some(ExprFnSig::Trait(bound.map_bound(|b| b.substs.type_at(0)), output, None)) }, _ => None, } }, ty::Projection(proj) => match cx.tcx.try_normalize_erasing_regions(cx.param_env, ty) { Ok(normalized_ty) if normalized_ty != ty => ty_sig(cx, normalized_ty), - _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty)), + _ => sig_for_projection(cx, proj).or_else(|| sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None)), }, - ty::Param(_) => sig_from_bounds(cx, ty), + ty::Param(_) => sig_from_bounds(cx, ty, cx.param_env.caller_bounds(), None), _ => None, } } -fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'tcx>> { +fn sig_from_bounds<'tcx>( + cx: &LateContext<'tcx>, + ty: Ty<'tcx>, + predicates: &'tcx [Predicate<'tcx>], + predicates_id: Option<DefId>, +) -> Option<ExprFnSig<'tcx>> { let mut inputs = None; let mut output = None; let lang_items = cx.tcx.lang_items(); - for (pred, _) in all_predicates_of(cx.tcx, cx.typeck_results().hir_owner.to_def_id()) { + for pred in predicates { match pred.kind().skip_binder() { PredicateKind::Trait(p) if (lang_items.fn_trait() == Some(p.def_id()) @@ -621,11 +631,12 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnS || lang_items.fn_once_trait() == Some(p.def_id())) && p.self_ty() == ty => { - if inputs.is_some() { + let i = pred.kind().rebind(p.trait_ref.substs.type_at(1)); + if inputs.map_or(false, |inputs| i != inputs) { // Multiple different fn trait impls. Is this even allowed? return None; } - inputs = Some(pred.kind().rebind(p.trait_ref.substs.type_at(1))); + inputs = Some(i); }, PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() @@ -641,7 +652,7 @@ fn sig_from_bounds<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnS } } - inputs.map(|ty| ExprFnSig::Trait(ty, output)) + inputs.map(|ty| ExprFnSig::Trait(ty, output, predicates_id)) } fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> Option<ExprFnSig<'tcx>> { @@ -661,14 +672,15 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O || lang_items.fn_mut_trait() == Some(p.def_id()) || lang_items.fn_once_trait() == Some(p.def_id())) => { - if inputs.is_some() { + let i = pred + .map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1))) + .subst(cx.tcx, ty.substs); + + if inputs.map_or(false, |inputs| inputs != i) { // Multiple different fn trait impls. Is this even allowed? return None; } - inputs = Some( - pred.map_bound(|pred| pred.kind().rebind(p.trait_ref.substs.type_at(1))) - .subst(cx.tcx, ty.substs), - ); + inputs = Some(i); }, PredicateKind::Projection(p) if Some(p.projection_ty.item_def_id) == lang_items.fn_once_output() => { if output.is_some() { @@ -684,7 +696,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: ProjectionTy<'tcx>) -> O } } - inputs.map(|ty| ExprFnSig::Trait(ty, output)) + inputs.map(|ty| ExprFnSig::Trait(ty, output, None)) } #[derive(Clone, Copy)] diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 23ba7c71277..7e14df4feea 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2022-07-28" +channel = "nightly-2022-08-11" components = ["cargo", "llvm-tools-preview", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr index 5331075885c..2aa4de490bc 100644 --- a/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr +++ b/src/tools/clippy/tests/ui-internal/check_clippy_version_attribute.stderr @@ -16,7 +16,7 @@ note: the lint level is defined here LL | #![deny(clippy::internal)] | ^^^^^^^^^^^^^^^^ = note: `#[deny(clippy::invalid_clippy_version_attribute)]` implied by `#[deny(clippy::internal)]` - = help: please use a valid sematic version, see `doc/adding_lints.md` + = help: please use a valid semantic version, see `doc/adding_lints.md` = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this item has an invalid `clippy::version` attribute @@ -31,7 +31,7 @@ LL | | report_in_external_macro: true LL | | } | |_^ | - = help: please use a valid sematic version, see `doc/adding_lints.md` + = help: please use a valid semantic version, see `doc/adding_lints.md` = note: this error originates in the macro `$crate::declare_tool_lint` which comes from the expansion of the macro `declare_tool_lint` (in Nightly builds, run with -Z macro-backtrace for more info) error: this lint is missing the `clippy::version` attribute or version value diff --git a/src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml b/src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml index 168675394d7..d48bab08f69 100644 --- a/src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml +++ b/src/tools/clippy/tests/ui-toml/bad_toml_type/clippy.toml @@ -1 +1 @@ -blacklisted-names = 42 +disallowed-names = 42 diff --git a/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr b/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr index c7bc261de6c..e3ec6019204 100644 --- a/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr +++ b/src/tools/clippy/tests/ui-toml/bad_toml_type/conf_bad_type.stderr @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `blacklisted-names` +error: error reading Clippy's configuration file `$DIR/clippy.toml`: invalid type: integer `42`, expected a sequence for key `disallowed-names` error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr b/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr deleted file mode 100644 index 9169bb0e866..00000000000 --- a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_names.rs:5:9 - | -LL | let foo = "bar"; - | ^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: use of a blacklisted/placeholder name `ducks` - --> $DIR/blacklisted_names.rs:7:9 - | -LL | let ducks = ["quack", "quack"]; - | ^^^^^ - -error: aborting due to 2 previous errors - diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml b/src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml deleted file mode 100644 index 0e052ef50f0..00000000000 --- a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -blacklisted-names = ["ducks", ".."] diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr b/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr deleted file mode 100644 index ec6f7f084f2..00000000000 --- a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.stderr +++ /dev/null @@ -1,10 +0,0 @@ -error: use of a blacklisted/placeholder name `ducks` - --> $DIR/blacklisted_names.rs:7:9 - | -LL | let ducks = ["quack", "quack"]; - | ^^^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: aborting due to previous error - diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml b/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml deleted file mode 100644 index 4582f1c0667..00000000000 --- a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -blacklisted-names = ["ducks"] diff --git a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml index ac47b195042..d79a98d05af 100644 --- a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml +++ b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/clippy.toml @@ -1,5 +1,6 @@ -# that one is an error -cyclomatic-complexity-threshold = 42 +# Expect errors from these deprecated configs +cyclomatic-complexity-threshold = 2 +blacklisted-names = [ "..", "wibble" ] # that one is white-listed [third-party] diff --git a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs index f328e4d9d04..b4e677ea124 100644 --- a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs +++ b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.rs @@ -1 +1,11 @@ fn main() {} + +#[warn(clippy::cognitive_complexity)] +fn cognitive_complexity() { + let x = vec![1, 2, 3]; + for i in x { + if i == 1 { + println!("{}", i); + } + } +} diff --git a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr index 90021a034a3..4c560299ebd 100644 --- a/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr +++ b/src/tools/clippy/tests/ui-toml/conf_deprecated_key/conf_deprecated_key.stderr @@ -1,4 +1,15 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead +warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead -error: aborting due to previous error +warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `blacklisted-names`. Please use `disallowed-names` instead + +error: the function has a cognitive complexity of (3/2) + --> $DIR/conf_deprecated_key.rs:4:4 + | +LL | fn cognitive_complexity() { + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::cognitive-complexity` implied by `-D warnings` + = help: you could split it up into multiple smaller functions + +error: aborting due to previous error; 2 warnings emitted diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml b/src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml new file mode 100644 index 00000000000..6df96a3c214 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/clippy.toml @@ -0,0 +1 @@ +disallowed-names = ["ducks", ".."] diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs index fb2395cf90b..a2e2b46c426 100644 --- a/src/tools/clippy/tests/ui-toml/blacklisted_names_append/blacklisted_names.rs +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.rs @@ -1,9 +1,9 @@ -#[warn(clippy::blacklisted_name)] +#[warn(clippy::disallowed_names)] fn main() { // `foo` is part of the default configuration let foo = "bar"; - // `ducks` was unrightfully blacklisted + // `ducks` was unrightfully disallowed let ducks = ["quack", "quack"]; // `fox` is okay let fox = ["what", "does", "the", "fox", "say", "?"]; diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr new file mode 100644 index 00000000000..23c3e96a8d0 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_append/disallowed_names.stderr @@ -0,0 +1,16 @@ +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_names.rs:5:9 + | +LL | let foo = "bar"; + | ^^^ + | + = note: `-D clippy::disallowed-names` implied by `-D warnings` + +error: use of a disallowed/placeholder name `ducks` + --> $DIR/disallowed_names.rs:7:9 + | +LL | let ducks = ["quack", "quack"]; + | ^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml new file mode 100644 index 00000000000..a1c515652d3 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/clippy.toml @@ -0,0 +1 @@ +disallowed-names = ["ducks"] diff --git a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs index fb2395cf90b..a2e2b46c426 100644 --- a/src/tools/clippy/tests/ui-toml/blacklisted_names_replace/blacklisted_names.rs +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.rs @@ -1,9 +1,9 @@ -#[warn(clippy::blacklisted_name)] +#[warn(clippy::disallowed_names)] fn main() { // `foo` is part of the default configuration let foo = "bar"; - // `ducks` was unrightfully blacklisted + // `ducks` was unrightfully disallowed let ducks = ["quack", "quack"]; // `fox` is okay let fox = ["what", "does", "the", "fox", "say", "?"]; diff --git a/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr new file mode 100644 index 00000000000..d961fa34074 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/disallowed_names_replace/disallowed_names.stderr @@ -0,0 +1,10 @@ +error: use of a disallowed/placeholder name `ducks` + --> $DIR/disallowed_names.rs:7:9 + | +LL | let ducks = ["quack", "quack"]; + | ^^^^^ + | + = note: `-D clippy::disallowed-names` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml b/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml new file mode 100644 index 00000000000..63a893cc6c7 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/duplicated_keys/clippy.toml @@ -0,0 +1,5 @@ +cognitive-complexity-threshold = 2 +# This is the deprecated name for the same key +cyclomatic-complexity-threshold = 3 +# Check we get duplication warning regardless of order +cognitive-complexity-threshold = 4 diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs new file mode 100644 index 00000000000..f328e4d9d04 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr new file mode 100644 index 00000000000..d99490a242d --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/duplicated_keys/duplicated_keys.stderr @@ -0,0 +1,8 @@ +error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive_complexity_threshold` (provided as `cyclomatic_complexity_threshold`) + +error: error reading Clippy's configuration file `$DIR/clippy.toml`: duplicate field `cognitive-complexity-threshold` + +warning: error reading Clippy's configuration file `$DIR/clippy.toml`: deprecated field `cyclomatic-complexity-threshold`. Please use `cognitive-complexity-threshold` instead + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr index 9cb2199ed21..c5d95cb8a14 100644 --- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr +++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.stderr @@ -5,7 +5,7 @@ LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | = note: `-D clippy::expect-used` implied by `-D warnings` - = help: if this value is an `None`, it will panic + = help: if this value is `None`, it will panic error: used `expect()` on `a Result` value --> $DIR/expect_used.rs:11:13 diff --git a/src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml deleted file mode 100644 index 6abe5a3bbc2..00000000000 --- a/src/tools/clippy/tests/ui-toml/toml_blacklist/clippy.toml +++ /dev/null @@ -1 +0,0 @@ -blacklisted-names = ["toto", "tata", "titi"] diff --git a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr b/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr deleted file mode 100644 index 84ba77851f7..00000000000 --- a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.stderr +++ /dev/null @@ -1,46 +0,0 @@ -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:6:9 - | -LL | fn test(toto: ()) {} - | ^^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:9:9 - | -LL | let toto = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:10:9 - | -LL | let tata = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:11:9 - | -LL | let titi = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `toto` - --> $DIR/conf_french_blacklisted_name.rs:17:10 - | -LL | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `tata` - --> $DIR/conf_french_blacklisted_name.rs:17:21 - | -LL | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `titi` - --> $DIR/conf_french_blacklisted_name.rs:17:28 - | -LL | (toto, Some(tata), titi @ Some(_)) => (), - | ^^^^ - -error: aborting due to 7 previous errors - diff --git a/src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml b/src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml new file mode 100644 index 00000000000..e4f0cb6df57 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/toml_disallow/clippy.toml @@ -0,0 +1 @@ +disallowed-names = ["toto", "tata", "titi"] diff --git a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs index cb35d0e8589..2f86b3eda4c 100644 --- a/src/tools/clippy/tests/ui-toml/toml_blacklist/conf_french_blacklisted_name.rs +++ b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.rs @@ -1,7 +1,7 @@ #![allow(dead_code)] #![allow(clippy::single_match)] #![allow(unused_variables)] -#![warn(clippy::blacklisted_name)] +#![warn(clippy::disallowed_names)] fn test(toto: ()) {} diff --git a/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr new file mode 100644 index 00000000000..9082c1c54c3 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/toml_disallow/conf_french_disallowed_name.stderr @@ -0,0 +1,46 @@ +error: use of a disallowed/placeholder name `toto` + --> $DIR/conf_french_disallowed_name.rs:6:9 + | +LL | fn test(toto: ()) {} + | ^^^^ + | + = note: `-D clippy::disallowed-names` implied by `-D warnings` + +error: use of a disallowed/placeholder name `toto` + --> $DIR/conf_french_disallowed_name.rs:9:9 + | +LL | let toto = 42; + | ^^^^ + +error: use of a disallowed/placeholder name `tata` + --> $DIR/conf_french_disallowed_name.rs:10:9 + | +LL | let tata = 42; + | ^^^^ + +error: use of a disallowed/placeholder name `titi` + --> $DIR/conf_french_disallowed_name.rs:11:9 + | +LL | let titi = 42; + | ^^^^ + +error: use of a disallowed/placeholder name `toto` + --> $DIR/conf_french_disallowed_name.rs:17:10 + | +LL | (toto, Some(tata), titi @ Some(_)) => (), + | ^^^^ + +error: use of a disallowed/placeholder name `tata` + --> $DIR/conf_french_disallowed_name.rs:17:21 + | +LL | (toto, Some(tata), titi @ Some(_)) => (), + | ^^^^ + +error: use of a disallowed/placeholder name `titi` + --> $DIR/conf_french_disallowed_name.rs:17:28 + | +LL | (toto, Some(tata), titi @ Some(_)) => (), + | ^^^^ + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr index fe5139c4768..9f8e778b3b9 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr @@ -12,6 +12,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie cognitive-complexity-threshold cyclomatic-complexity-threshold disallowed-methods + disallowed-names disallowed-types doc-valid-idents enable-raw-pointer-heuristic-for-send diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed index 7bde72e4b6b..795f435f24c 100644 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed +++ b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed @@ -27,6 +27,14 @@ fn main() { let r: Result<Foo, Foo> = Ok(Foo); assert!(r.is_ok()); + // test ok with some messages + let r: Result<Foo, DebugFoo> = Ok(Foo); + assert!(r.is_ok(), "oops"); + + // test ok with unit error + let r: Result<Foo, ()> = Ok(Foo); + assert!(r.is_ok()); + // test temporary ok fn get_ok() -> Result<Foo, DebugFoo> { Ok(Foo) diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.rs b/src/tools/clippy/tests/ui/assertions_on_result_states.rs index 4c5af81efc2..1101aec1e1b 100644 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.rs +++ b/src/tools/clippy/tests/ui/assertions_on_result_states.rs @@ -27,6 +27,14 @@ fn main() { let r: Result<Foo, Foo> = Ok(Foo); assert!(r.is_ok()); + // test ok with some messages + let r: Result<Foo, DebugFoo> = Ok(Foo); + assert!(r.is_ok(), "oops"); + + // test ok with unit error + let r: Result<Foo, ()> = Ok(Foo); + assert!(r.is_ok()); + // test temporary ok fn get_ok() -> Result<Foo, DebugFoo> { Ok(Foo) diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr index 13c2dd877a9..97a5f3dfca4 100644 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.stderr +++ b/src/tools/clippy/tests/ui/assertions_on_result_states.stderr @@ -7,31 +7,31 @@ LL | assert!(r.is_ok()); = note: `-D clippy::assertions-on-result-states` implied by `-D warnings` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:34:5 + --> $DIR/assertions_on_result_states.rs:42:5 | LL | assert!(get_ok().is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok().unwrap()` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:37:5 + --> $DIR/assertions_on_result_states.rs:45:5 | LL | assert!(get_ok_macro!().is_ok()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `get_ok_macro!().unwrap()` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:50:5 + --> $DIR/assertions_on_result_states.rs:58:5 | LL | assert!(r.is_ok()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` error: called `assert!` with `Result::is_ok` - --> $DIR/assertions_on_result_states.rs:56:9 + --> $DIR/assertions_on_result_states.rs:64:9 | LL | assert!(r.is_ok()); | ^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap()` error: called `assert!` with `Result::is_err` - --> $DIR/assertions_on_result_states.rs:64:5 + --> $DIR/assertions_on_result_states.rs:72:5 | LL | assert!(r.is_err()); | ^^^^^^^^^^^^^^^^^^^ help: replace with: `r.unwrap_err()` diff --git a/src/tools/clippy/tests/ui/blacklisted_name.stderr b/src/tools/clippy/tests/ui/blacklisted_name.stderr deleted file mode 100644 index 70dbdaece8b..00000000000 --- a/src/tools/clippy/tests/ui/blacklisted_name.stderr +++ /dev/null @@ -1,88 +0,0 @@ -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:11:9 - | -LL | fn test(foo: ()) {} - | ^^^ - | - = note: `-D clippy::blacklisted-name` implied by `-D warnings` - -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:14:9 - | -LL | let foo = 42; - | ^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:15:9 - | -LL | let baz = 42; - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:16:9 - | -LL | let quux = 42; - | ^^^^ - -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:27:10 - | -LL | (foo, Some(baz), quux @ Some(_)) => (), - | ^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:27:20 - | -LL | (foo, Some(baz), quux @ Some(_)) => (), - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:27:26 - | -LL | (foo, Some(baz), quux @ Some(_)) => (), - | ^^^^ - -error: use of a blacklisted/placeholder name `foo` - --> $DIR/blacklisted_name.rs:32:19 - | -LL | fn issue_1647(mut foo: u8) { - | ^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:33:13 - | -LL | let mut baz = 0; - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:34:21 - | -LL | if let Some(mut quux) = Some(42) {} - | ^^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:38:13 - | -LL | let ref baz = 0; - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:39:21 - | -LL | if let Some(ref quux) = Some(42) {} - | ^^^^ - -error: use of a blacklisted/placeholder name `baz` - --> $DIR/blacklisted_name.rs:43:17 - | -LL | let ref mut baz = 0; - | ^^^ - -error: use of a blacklisted/placeholder name `quux` - --> $DIR/blacklisted_name.rs:44:25 - | -LL | if let Some(ref mut quux) = Some(42) {} - | ^^^^ - -error: aborting due to 14 previous errors - diff --git a/src/tools/clippy/tests/ui/borrow_box.rs b/src/tools/clippy/tests/ui/borrow_box.rs index b606f773cfb..35ed87b0f18 100644 --- a/src/tools/clippy/tests/ui/borrow_box.rs +++ b/src/tools/clippy/tests/ui/borrow_box.rs @@ -1,5 +1,5 @@ #![deny(clippy::borrowed_box)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] #![allow(unused_variables)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/box_collection.rs b/src/tools/clippy/tests/ui/box_collection.rs index 1a74cdb3ff6..0780c8f0586 100644 --- a/src/tools/clippy/tests/ui/box_collection.rs +++ b/src/tools/clippy/tests/ui/box_collection.rs @@ -2,7 +2,7 @@ #![allow( clippy::boxed_local, clippy::needless_pass_by_value, - clippy::blacklisted_name, + clippy::disallowed_names, unused )] diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed index a68b32b097e..7ecefd7b134 100644 --- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed +++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed @@ -26,4 +26,6 @@ fn main() { let _ = a.unsigned_abs() as u32; let _ = a.unsigned_abs() as u64; let _ = a.unsigned_abs() as u128; + + let _ = (x as i64 - y as i64).unsigned_abs() as u32; } diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs index 110fbc6c2df..30c603fca9a 100644 --- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs +++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs @@ -26,4 +26,6 @@ fn main() { let _ = a.abs() as u32; let _ = a.abs() as u64; let _ = a.abs() as u128; + + let _ = (x as i64 - y as i64).abs() as u32; } diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr index 02c24e10659..04553774526 100644 --- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr +++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.stderr @@ -96,5 +96,11 @@ error: casting the result of `isize::abs()` to u128 LL | let _ = a.abs() as u128; | ^^^^^^^ help: replace with: `a.unsigned_abs()` -error: aborting due to 16 previous errors +error: casting the result of `i64::abs()` to u32 + --> $DIR/cast_abs_to_unsigned.rs:30:13 + | +LL | let _ = (x as i64 - y as i64).abs() as u32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `(x as i64 - y as i64).unsigned_abs()` + +error: aborting due to 17 previous errors diff --git a/src/tools/clippy/tests/ui/clone_on_copy.fixed b/src/tools/clippy/tests/ui/clone_on_copy.fixed index dc062762604..72b12227098 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.fixed +++ b/src/tools/clippy/tests/ui/clone_on_copy.fixed @@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool { ch.is_ascii() } -fn clone_on_copy() { +fn clone_on_copy() -> Option<(i32)> { 42; vec![1].clone(); // ok, not a Copy type @@ -71,4 +71,9 @@ fn clone_on_copy() { // Issue #5436 let mut vec = Vec::new(); vec.push(42); + + // Issue #9277 + let opt: &Option<i32> = &None; + let value = (*opt)?; // operator precedence needed (*opt)? + None } diff --git a/src/tools/clippy/tests/ui/clone_on_copy.rs b/src/tools/clippy/tests/ui/clone_on_copy.rs index 8c39d0d55dd..03e210ebad9 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.rs +++ b/src/tools/clippy/tests/ui/clone_on_copy.rs @@ -21,7 +21,7 @@ fn is_ascii(ch: char) -> bool { ch.is_ascii() } -fn clone_on_copy() { +fn clone_on_copy() -> Option<(i32)> { 42.clone(); vec![1].clone(); // ok, not a Copy type @@ -71,4 +71,9 @@ fn clone_on_copy() { // Issue #5436 let mut vec = Vec::new(); vec.push(42.clone()); + + // Issue #9277 + let opt: &Option<i32> = &None; + let value = opt.clone()?; // operator precedence needed (*opt)? + None } diff --git a/src/tools/clippy/tests/ui/clone_on_copy.stderr b/src/tools/clippy/tests/ui/clone_on_copy.stderr index 861543d0aa9..42ae227777c 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.stderr +++ b/src/tools/clippy/tests/ui/clone_on_copy.stderr @@ -48,5 +48,11 @@ error: using `clone` on type `i32` which implements the `Copy` trait LL | vec.push(42.clone()); | ^^^^^^^^^^ help: try removing the `clone` call: `42` -error: aborting due to 8 previous errors +error: using `clone` on type `std::option::Option<i32>` which implements the `Copy` trait + --> $DIR/clone_on_copy.rs:77:17 + | +LL | let value = opt.clone()?; // operator precedence needed (*opt)? + | ^^^^^^^^^^^ help: try dereferencing it: `(*opt)` + +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/crashes/ice-2760.rs b/src/tools/clippy/tests/ui/crashes/ice-2760.rs index f1a229f3f4f..61ef2480498 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-2760.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-2760.rs @@ -1,6 +1,6 @@ #![allow( unused_variables, - clippy::blacklisted_name, + clippy::disallowed_names, clippy::needless_pass_by_value, dead_code )] diff --git a/src/tools/clippy/tests/ui/crashes/ice-3462.rs b/src/tools/clippy/tests/ui/crashes/ice-3462.rs index 02c49aa0d7c..b402052882a 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3462.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3462.rs @@ -1,5 +1,5 @@ #![warn(clippy::all)] -#![allow(clippy::blacklisted_name, clippy::equatable_if_let)] +#![allow(clippy::disallowed_names, clippy::equatable_if_let)] #![allow(unused)] /// Test for https://github.com/rust-lang/rust-clippy/issues/3462 diff --git a/src/tools/clippy/tests/ui/crashes/regressions.rs b/src/tools/clippy/tests/ui/crashes/regressions.rs index 6f9d98bbfe7..55a8b403407 100644 --- a/src/tools/clippy/tests/ui/crashes/regressions.rs +++ b/src/tools/clippy/tests/ui/crashes/regressions.rs @@ -1,4 +1,4 @@ -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] pub fn foo(bar: *const u8) { println!("{:#p}", bar); diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs index 156c88e2e45..a7da8f89aa3 100644 --- a/src/tools/clippy/tests/ui/def_id_nocore.rs +++ b/src/tools/clippy/tests/ui/def_id_nocore.rs @@ -1,4 +1,3 @@ -// ignore-windows // ignore-macos #![feature(no_core, lang_items, start)] diff --git a/src/tools/clippy/tests/ui/def_id_nocore.stderr b/src/tools/clippy/tests/ui/def_id_nocore.stderr index 40d355e9a2e..6210d7c6cfd 100644 --- a/src/tools/clippy/tests/ui/def_id_nocore.stderr +++ b/src/tools/clippy/tests/ui/def_id_nocore.stderr @@ -1,5 +1,5 @@ error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/def_id_nocore.rs:28:19 + --> $DIR/def_id_nocore.rs:27:19 | LL | pub fn as_ref(self) -> &'static str { | ^^^^ diff --git a/src/tools/clippy/tests/ui/default_trait_access.fixed b/src/tools/clippy/tests/ui/default_trait_access.fixed index 264dd4efaeb..fce66eb1759 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.fixed +++ b/src/tools/clippy/tests/ui/default_trait_access.fixed @@ -1,8 +1,12 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![allow(unused_imports, dead_code)] #![deny(clippy::default_trait_access)] +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; use std::default; use std::default::Default as D2; use std::string; @@ -51,6 +55,8 @@ fn main() { ..Default::default() }; + let _s21: String = with_span!(s Default::default()); + println!( "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]", s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, diff --git a/src/tools/clippy/tests/ui/default_trait_access.rs b/src/tools/clippy/tests/ui/default_trait_access.rs index a0930fab8e7..3e8e898b7bc 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.rs +++ b/src/tools/clippy/tests/ui/default_trait_access.rs @@ -1,8 +1,12 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![allow(unused_imports, dead_code)] #![deny(clippy::default_trait_access)] +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; use std::default; use std::default::Default as D2; use std::string; @@ -51,6 +55,8 @@ fn main() { ..Default::default() }; + let _s21: String = with_span!(s Default::default()); + println!( "[{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}] [{:?}]", s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15, s16, s17, s18, s19, s20, diff --git a/src/tools/clippy/tests/ui/default_trait_access.stderr b/src/tools/clippy/tests/ui/default_trait_access.stderr index df8a5b94ddc..3493de37a55 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.stderr +++ b/src/tools/clippy/tests/ui/default_trait_access.stderr @@ -1,53 +1,53 @@ error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:11:22 + --> $DIR/default_trait_access.rs:15:22 | LL | let s1: String = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` | note: the lint level is defined here - --> $DIR/default_trait_access.rs:4:9 + --> $DIR/default_trait_access.rs:5:9 | LL | #![deny(clippy::default_trait_access)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:15:22 + --> $DIR/default_trait_access.rs:19:22 | LL | let s3: String = D2::default(); | ^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:17:22 + --> $DIR/default_trait_access.rs:21:22 | LL | let s4: String = std::default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `std::string::String::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:21:22 + --> $DIR/default_trait_access.rs:25:22 | LL | let s6: String = default::Default::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::string::String::default()` error: calling `GenericDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:31:46 + --> $DIR/default_trait_access.rs:35:46 | LL | let s11: GenericDerivedDefault<String> = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `GenericDerivedDefault::default()` error: calling `TupleDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:37:36 + --> $DIR/default_trait_access.rs:41:36 | LL | let s14: TupleDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleDerivedDefault::default()` error: calling `ArrayDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:39:36 + --> $DIR/default_trait_access.rs:43:36 | LL | let s15: ArrayDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `ArrayDerivedDefault::default()` error: calling `TupleStructDerivedDefault::default()` is more clear than this expression - --> $DIR/default_trait_access.rs:43:42 + --> $DIR/default_trait_access.rs:47:42 | LL | let s17: TupleStructDerivedDefault = Default::default(); | ^^^^^^^^^^^^^^^^^^ help: try: `TupleStructDerivedDefault::default()` diff --git a/src/tools/clippy/tests/ui/blacklisted_name.rs b/src/tools/clippy/tests/ui/disallowed_names.rs index 27df732a088..e937c49f389 100644 --- a/src/tools/clippy/tests/ui/blacklisted_name.rs +++ b/src/tools/clippy/tests/ui/disallowed_names.rs @@ -6,7 +6,7 @@ unused_mut, unused_variables )] -#![warn(clippy::blacklisted_name)] +#![warn(clippy::disallowed_names)] fn test(foo: ()) {} @@ -46,7 +46,7 @@ fn issue_1647_ref_mut() { mod tests { fn issue_7305() { - // `blacklisted_name` lint should not be triggered inside of the test code. + // `disallowed_names` lint should not be triggered inside of the test code. let foo = 0; // Check that even in nested functions warning is still not triggered. diff --git a/src/tools/clippy/tests/ui/disallowed_names.stderr b/src/tools/clippy/tests/ui/disallowed_names.stderr new file mode 100644 index 00000000000..78cb55096ff --- /dev/null +++ b/src/tools/clippy/tests/ui/disallowed_names.stderr @@ -0,0 +1,88 @@ +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_names.rs:11:9 + | +LL | fn test(foo: ()) {} + | ^^^ + | + = note: `-D clippy::disallowed-names` implied by `-D warnings` + +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_names.rs:14:9 + | +LL | let foo = 42; + | ^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_names.rs:15:9 + | +LL | let baz = 42; + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_names.rs:16:9 + | +LL | let quux = 42; + | ^^^^ + +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_names.rs:27:10 + | +LL | (foo, Some(baz), quux @ Some(_)) => (), + | ^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_names.rs:27:20 + | +LL | (foo, Some(baz), quux @ Some(_)) => (), + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_names.rs:27:26 + | +LL | (foo, Some(baz), quux @ Some(_)) => (), + | ^^^^ + +error: use of a disallowed/placeholder name `foo` + --> $DIR/disallowed_names.rs:32:19 + | +LL | fn issue_1647(mut foo: u8) { + | ^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_names.rs:33:13 + | +LL | let mut baz = 0; + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_names.rs:34:21 + | +LL | if let Some(mut quux) = Some(42) {} + | ^^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_names.rs:38:13 + | +LL | let ref baz = 0; + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_names.rs:39:21 + | +LL | if let Some(ref quux) = Some(42) {} + | ^^^^ + +error: use of a disallowed/placeholder name `baz` + --> $DIR/disallowed_names.rs:43:17 + | +LL | let ref mut baz = 0; + | ^^^ + +error: use of a disallowed/placeholder name `quux` + --> $DIR/disallowed_names.rs:44:25 + | +LL | if let Some(ref mut quux) = Some(42) {} + | ^^^^ + +error: aborting due to 14 previous errors + diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.rs b/src/tools/clippy/tests/ui/diverging_sub_expression.rs index e27f9fea708..e8f992e6dde 100644 --- a/src/tools/clippy/tests/ui/diverging_sub_expression.rs +++ b/src/tools/clippy/tests/ui/diverging_sub_expression.rs @@ -1,5 +1,5 @@ #![warn(clippy::diverging_sub_expression)] -#![allow(clippy::match_same_arms, clippy::logic_bug)] +#![allow(clippy::match_same_arms, clippy::overly_complex_bool_expr)] #[allow(clippy::empty_loop)] fn diverge() -> ! { loop {} diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.rs b/src/tools/clippy/tests/ui/empty_loop_no_std.rs index 235e0fc5179..e742b396fcd 100644 --- a/src/tools/clippy/tests/ui/empty_loop_no_std.rs +++ b/src/tools/clippy/tests/ui/empty_loop_no_std.rs @@ -1,6 +1,5 @@ // compile-flags: -Clink-arg=-nostartfiles // ignore-macos -// ignore-windows #![warn(clippy::empty_loop)] #![feature(lang_items, start, libc)] diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr index 520248fcb68..5ded35a6f0d 100644 --- a/src/tools/clippy/tests/ui/empty_loop_no_std.stderr +++ b/src/tools/clippy/tests/ui/empty_loop_no_std.stderr @@ -1,5 +1,5 @@ error: empty `loop {}` wastes CPU cycles - --> $DIR/empty_loop_no_std.rs:14:5 + --> $DIR/empty_loop_no_std.rs:13:5 | LL | loop {} | ^^^^^^^ @@ -8,7 +8,7 @@ LL | loop {} = help: you should either use `panic!()` or add a call pausing or sleeping the thread to the loop body error: empty `loop {}` wastes CPU cycles - --> $DIR/empty_loop_no_std.rs:26:5 + --> $DIR/empty_loop_no_std.rs:25:5 | LL | loop {} | ^^^^^^^ diff --git a/src/tools/clippy/tests/ui/expect.stderr b/src/tools/clippy/tests/ui/expect.stderr index 9d3fc7df15c..ab28aac4556 100644 --- a/src/tools/clippy/tests/ui/expect.stderr +++ b/src/tools/clippy/tests/ui/expect.stderr @@ -5,7 +5,7 @@ LL | let _ = opt.expect(""); | ^^^^^^^^^^^^^^ | = note: `-D clippy::expect-used` implied by `-D warnings` - = help: if this value is an `None`, it will panic + = help: if this value is `None`, it will panic error: used `expect()` on `a Result` value --> $DIR/expect.rs:10:13 diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs index 28b37f96e91..0415e33b3fa 100644 --- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs +++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.rs @@ -98,7 +98,7 @@ mod clippy_ok { let _ = if true { 42 } else { 42 }; } - #[expect(clippy::logic_bug)] + #[expect(clippy::overly_complex_bool_expr)] fn burger() { let a = false; let b = true; @@ -127,7 +127,7 @@ mod clippy_warn { let _ = if true { 33 } else { 42 }; } - #[expect(clippy::logic_bug)] + #[expect(clippy::overly_complex_bool_expr)] fn burger() { let a = false; let b = true; diff --git a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr index db29e85a821..7ce9e855b5e 100644 --- a/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr +++ b/src/tools/clippy/tests/ui/expect_tool_lint_rfc_2383.stderr @@ -33,8 +33,8 @@ LL | #[expect(clippy::if_same_then_else)] error: this lint expectation is unfulfilled --> $DIR/expect_tool_lint_rfc_2383.rs:130:14 | -LL | #[expect(clippy::logic_bug)] - | ^^^^^^^^^^^^^^^^^ +LL | #[expect(clippy::overly_complex_bool_expr)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed index a650fdc1f89..d1d35e5c0eb 100644 --- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed @@ -1,5 +1,6 @@ // run-rustfix +#![feature(closure_lifetime_binder)] #![warn(clippy::explicit_auto_deref)] #![allow( dead_code, @@ -67,6 +68,8 @@ fn main() { let s = String::new(); let _: &str = &s; + let _: &str = &{ String::new() }; + let _: &str = &mut { String::new() }; let _ = &*s; // Don't lint. Inferred type would change. let _: &_ = &*s; // Don't lint. Inferred type would change. @@ -215,4 +218,52 @@ fn main() { let s = &"str"; let _ = || return *s; let _ = || -> &'static str { return s }; + + struct X; + struct Y(X); + impl core::ops::Deref for Y { + type Target = X; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let _: &X = &*{ Y(X) }; + let _: &X = &*match 0 { + #[rustfmt::skip] + 0 => { Y(X) }, + _ => panic!(), + }; + let _: &X = &*if true { Y(X) } else { panic!() }; + + fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U { + x + } + + let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x }; + fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any { + &**x + } + + let x = String::new(); + let _: *const str = &*x; + + struct S7([u32; 1]); + impl core::ops::Deref for S7 { + type Target = [u32; 1]; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let x = S7([0]); + let _: &[u32] = &*x; + + let c1 = |_: &Vec<&u32>| {}; + let x = &&vec![&1u32]; + c1(x); + let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { + if b { + return x; + } + x + }; } diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs index 8f4f352576a..deedafad153 100644 --- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs @@ -1,5 +1,6 @@ // run-rustfix +#![feature(closure_lifetime_binder)] #![warn(clippy::explicit_auto_deref)] #![allow( dead_code, @@ -67,6 +68,8 @@ fn main() { let s = String::new(); let _: &str = &*s; + let _: &str = &*{ String::new() }; + let _: &str = &mut *{ String::new() }; let _ = &*s; // Don't lint. Inferred type would change. let _: &_ = &*s; // Don't lint. Inferred type would change. @@ -215,4 +218,52 @@ fn main() { let s = &"str"; let _ = || return *s; let _ = || -> &'static str { return *s }; + + struct X; + struct Y(X); + impl core::ops::Deref for Y { + type Target = X; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let _: &X = &*{ Y(X) }; + let _: &X = &*match 0 { + #[rustfmt::skip] + 0 => { Y(X) }, + _ => panic!(), + }; + let _: &X = &*if true { Y(X) } else { panic!() }; + + fn deref_to_u<U, T: core::ops::Deref<Target = U>>(x: &T) -> &U { + &**x + } + + let _ = |x: &'static Box<dyn Iterator<Item = u32>>| -> &'static dyn Iterator<Item = u32> { &**x }; + fn ret_any(x: &Box<dyn std::any::Any>) -> &dyn std::any::Any { + &**x + } + + let x = String::new(); + let _: *const str = &*x; + + struct S7([u32; 1]); + impl core::ops::Deref for S7 { + type Target = [u32; 1]; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + let x = S7([0]); + let _: &[u32] = &*x; + + let c1 = |_: &Vec<&u32>| {}; + let x = &&vec![&1u32]; + c1(*x); + let _ = for<'a, 'b> |x: &'a &'a Vec<&'b u32>, b: bool| -> &'a Vec<&'b u32> { + if b { + return *x; + } + *x + }; } diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr index 92765307ea7..91863abcc5d 100644 --- a/src/tools/clippy/tests/ui/explicit_auto_deref.stderr +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.stderr @@ -1,202 +1,238 @@ error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:69:20 + --> $DIR/explicit_auto_deref.rs:70:19 | LL | let _: &str = &*s; - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` | = note: `-D clippy::explicit-auto-deref` implied by `-D warnings` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:73:12 + --> $DIR/explicit_auto_deref.rs:71:19 + | +LL | let _: &str = &*{ String::new() }; + | ^^^^^^^^^^^^^^^^^^^ help: try this: `&{ String::new() }` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:72:19 + | +LL | let _: &str = &mut *{ String::new() }; + | ^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `&mut { String::new() }` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:76:11 | LL | f_str(&*s); - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:77:14 + --> $DIR/explicit_auto_deref.rs:80:13 | LL | f_str_t(&*s, &*s); // Don't lint second param. - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:80:25 + --> $DIR/explicit_auto_deref.rs:83:24 | LL | let _: &Box<i32> = &**b; - | ^^^ help: try this: `b` + | ^^^^ help: try this: `&b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:86:8 + --> $DIR/explicit_auto_deref.rs:89:7 | LL | c(&*s); - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:92:9 + --> $DIR/explicit_auto_deref.rs:95:9 | LL | &**x | ^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:96:11 + --> $DIR/explicit_auto_deref.rs:99:11 | LL | { &**x } | ^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:100:9 + --> $DIR/explicit_auto_deref.rs:103:9 | LL | &**{ x } | ^^^^^^^^ help: try this: `{ x }` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:104:9 + --> $DIR/explicit_auto_deref.rs:107:9 | LL | &***x | ^^^^^ help: try this: `x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:121:13 + --> $DIR/explicit_auto_deref.rs:124:12 | LL | f1(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:122:13 + --> $DIR/explicit_auto_deref.rs:125:12 | LL | f2(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:123:13 + --> $DIR/explicit_auto_deref.rs:126:12 | LL | f3(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:124:28 + --> $DIR/explicit_auto_deref.rs:127:27 | LL | f4.callable_str()(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:125:13 + --> $DIR/explicit_auto_deref.rs:128:12 | LL | f5(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:126:13 + --> $DIR/explicit_auto_deref.rs:129:12 | LL | f6(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:127:28 + --> $DIR/explicit_auto_deref.rs:130:27 | LL | f7.callable_str()(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:128:26 + --> $DIR/explicit_auto_deref.rs:131:25 | LL | f8.callable_t()(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:129:13 + --> $DIR/explicit_auto_deref.rs:132:12 | LL | f9(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:130:14 + --> $DIR/explicit_auto_deref.rs:133:13 | LL | f10(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:131:27 + --> $DIR/explicit_auto_deref.rs:134:26 | LL | f11.callable_t()(&*x); - | ^^ help: try this: `x` + | ^^^ help: try this: `&x` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:135:17 + --> $DIR/explicit_auto_deref.rs:138:16 | LL | let _ = S1(&*s); - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:140:22 + --> $DIR/explicit_auto_deref.rs:143:21 | LL | let _ = S2 { s: &*s }; - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:156:30 + --> $DIR/explicit_auto_deref.rs:159:30 | LL | let _ = Self::S1(&**s); | ^^^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:157:35 + --> $DIR/explicit_auto_deref.rs:160:35 | LL | let _ = Self::S2 { s: &**s }; | ^^^^ help: try this: `s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:160:21 + --> $DIR/explicit_auto_deref.rs:163:20 | LL | let _ = E1::S1(&*s); - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:161:26 + --> $DIR/explicit_auto_deref.rs:164:25 | LL | let _ = E1::S2 { s: &*s }; - | ^^ help: try this: `s` + | ^^^ help: try this: `&s` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:179:13 + --> $DIR/explicit_auto_deref.rs:182:13 | LL | let _ = (*b).foo; | ^^^^ help: try this: `b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:180:13 + --> $DIR/explicit_auto_deref.rs:183:13 | LL | let _ = (**b).foo; | ^^^^^ help: try this: `b` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:195:19 + --> $DIR/explicit_auto_deref.rs:198:19 | LL | let _ = f_str(*ref_str); | ^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:197:19 + --> $DIR/explicit_auto_deref.rs:200:19 | LL | let _ = f_str(**ref_ref_str); | ^^^^^^^^^^^^^ help: try this: `ref_ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:207:13 + --> $DIR/explicit_auto_deref.rs:210:13 | LL | f_str(&&*ref_str); // `needless_borrow` will suggest removing both references | ^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:208:12 + --> $DIR/explicit_auto_deref.rs:211:12 | LL | f_str(&&**ref_str); // `needless_borrow` will suggest removing only one reference | ^^^^^^^^^^ help: try this: `ref_str` error: deref which would be done by auto-deref - --> $DIR/explicit_auto_deref.rs:217:41 + --> $DIR/explicit_auto_deref.rs:220:41 | LL | let _ = || -> &'static str { return *s }; | ^^ help: try this: `s` -error: aborting due to 33 previous errors +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:239:9 + | +LL | &**x + | ^^^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:262:8 + | +LL | c1(*x); + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:265:20 + | +LL | return *x; + | ^^ help: try this: `x` + +error: deref which would be done by auto-deref + --> $DIR/explicit_auto_deref.rs:267:9 + | +LL | *x + | ^^ help: try this: `x` + +error: aborting due to 39 previous errors diff --git a/src/tools/clippy/tests/ui/if_same_then_else.rs b/src/tools/clippy/tests/ui/if_same_then_else.rs index 2598c2ab426..07d2002eb27 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else.rs +++ b/src/tools/clippy/tests/ui/if_same_then_else.rs @@ -1,6 +1,6 @@ #![warn(clippy::if_same_then_else)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_names, clippy::eq_op, clippy::never_loop, clippy::no_effect, diff --git a/src/tools/clippy/tests/ui/if_same_then_else2.rs b/src/tools/clippy/tests/ui/if_same_then_else2.rs index 0016009a02f..58167f4446d 100644 --- a/src/tools/clippy/tests/ui/if_same_then_else2.rs +++ b/src/tools/clippy/tests/ui/if_same_then_else2.rs @@ -1,6 +1,6 @@ #![warn(clippy::if_same_then_else)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_names, clippy::collapsible_else_if, clippy::equatable_if_let, clippy::collapsible_if, diff --git a/src/tools/clippy/tests/ui/ifs_same_cond.rs b/src/tools/clippy/tests/ui/ifs_same_cond.rs index 80e9839ff40..9850fc0919e 100644 --- a/src/tools/clippy/tests/ui/ifs_same_cond.rs +++ b/src/tools/clippy/tests/ui/ifs_same_cond.rs @@ -32,9 +32,9 @@ fn ifs_same_cond() { }; let mut v = vec![1]; - if v.pop() == None { + if v.pop().is_none() { // ok, functions - } else if v.pop() == None { + } else if v.pop().is_none() { } if v.len() == 42 { diff --git a/src/tools/clippy/tests/ui/iter_skip_next.fixed b/src/tools/clippy/tests/ui/iter_skip_next.fixed index 2db4c2bee7f..d56d623b526 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next.fixed +++ b/src/tools/clippy/tests/ui/iter_skip_next.fixed @@ -2,7 +2,7 @@ // aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::iter_nth)] #![allow(unused_mut, dead_code)] diff --git a/src/tools/clippy/tests/ui/iter_skip_next.rs b/src/tools/clippy/tests/ui/iter_skip_next.rs index 692edb9aed9..3ec5d1b8214 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next.rs +++ b/src/tools/clippy/tests/ui/iter_skip_next.rs @@ -2,7 +2,7 @@ // aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::iter_nth)] #![allow(unused_mut, dead_code)] diff --git a/src/tools/clippy/tests/ui/let_if_seq.rs b/src/tools/clippy/tests/ui/let_if_seq.rs index c5cb2eb1fe1..959567f6867 100644 --- a/src/tools/clippy/tests/ui/let_if_seq.rs +++ b/src/tools/clippy/tests/ui/let_if_seq.rs @@ -2,7 +2,7 @@ unused_variables, unused_assignments, clippy::similar_names, - clippy::blacklisted_name, + clippy::disallowed_names, clippy::branches_sharing_code, clippy::needless_late_init )] diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed index d0bc640db88..65598f1eacc 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed +++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed @@ -17,7 +17,7 @@ fn main() { let c = Some(2); if !a.is_empty() && a.len() == 3 - && c != None + && c.is_some() && !a.is_empty() && a.len() == 3 && !a.is_empty() diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed index d0bc640db88..65598f1eacc 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed +++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed @@ -17,7 +17,7 @@ fn main() { let c = Some(2); if !a.is_empty() && a.len() == 3 - && c != None + && c.is_some() && !a.is_empty() && a.len() == 3 && !a.is_empty() diff --git a/src/tools/clippy/tests/ui/manual_assert.fixed b/src/tools/clippy/tests/ui/manual_assert.fixed index 6c2a25c37d8..a2393674fe6 100644 --- a/src/tools/clippy/tests/ui/manual_assert.fixed +++ b/src/tools/clippy/tests/ui/manual_assert.fixed @@ -11,7 +11,7 @@ fn main() { let c = Some(2); if !a.is_empty() && a.len() == 3 - && c != None + && c.is_some() && !a.is_empty() && a.len() == 3 && !a.is_empty() diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs index 027747d8386..4d2706dd621 100644 --- a/src/tools/clippy/tests/ui/manual_assert.rs +++ b/src/tools/clippy/tests/ui/manual_assert.rs @@ -17,7 +17,7 @@ fn main() { let c = Some(2); if !a.is_empty() && a.len() == 3 - && c != None + && c.is_some() && !a.is_empty() && a.len() == 3 && !a.is_empty() diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed b/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed new file mode 100644 index 00000000000..0fa776b7b2e --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed @@ -0,0 +1,27 @@ +// run-rustfix +#![warn(clippy::manual_instant_elapsed)] +#![allow(clippy::unnecessary_operation)] +#![allow(unused_variables)] +#![allow(unused_must_use)] + +use std::time::Instant; + +fn main() { + let prev_instant = Instant::now(); + + { + // don't influence + let another_instant = Instant::now(); + } + + let duration = prev_instant.elapsed(); + + // don't catch + let duration = prev_instant.elapsed(); + + Instant::now() - duration; + + let ref_to_instant = &Instant::now(); + + (*ref_to_instant).elapsed(); // to ensure parens are added correctly +} diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.rs b/src/tools/clippy/tests/ui/manual_instant_elapsed.rs new file mode 100644 index 00000000000..5b11b84535d --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.rs @@ -0,0 +1,27 @@ +// run-rustfix +#![warn(clippy::manual_instant_elapsed)] +#![allow(clippy::unnecessary_operation)] +#![allow(unused_variables)] +#![allow(unused_must_use)] + +use std::time::Instant; + +fn main() { + let prev_instant = Instant::now(); + + { + // don't influence + let another_instant = Instant::now(); + } + + let duration = Instant::now() - prev_instant; + + // don't catch + let duration = prev_instant.elapsed(); + + Instant::now() - duration; + + let ref_to_instant = &Instant::now(); + + Instant::now() - *ref_to_instant; // to ensure parens are added correctly +} diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr b/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr new file mode 100644 index 00000000000..5537f5642a2 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.stderr @@ -0,0 +1,16 @@ +error: manual implementation of `Instant::elapsed` + --> $DIR/manual_instant_elapsed.rs:17:20 + | +LL | let duration = Instant::now() - prev_instant; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `prev_instant.elapsed()` + | + = note: `-D clippy::manual-instant-elapsed` implied by `-D warnings` + +error: manual implementation of `Instant::elapsed` + --> $DIR/manual_instant_elapsed.rs:26:5 + | +LL | Instant::now() - *ref_to_instant; // to ensure parens are added correctly + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `(*ref_to_instant).elapsed()` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_ok_or.fixed b/src/tools/clippy/tests/ui/manual_ok_or.fixed index 887a97d7a01..d864f855453 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.fixed +++ b/src/tools/clippy/tests/ui/manual_ok_or.fixed @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::manual_ok_or)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::redundant_closure)] #![allow(dead_code)] #![allow(unused_must_use)] diff --git a/src/tools/clippy/tests/ui/manual_ok_or.rs b/src/tools/clippy/tests/ui/manual_ok_or.rs index 3c99872f502..6264768460e 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.rs +++ b/src/tools/clippy/tests/ui/manual_ok_or.rs @@ -1,6 +1,6 @@ // run-rustfix #![warn(clippy::manual_ok_or)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] #![allow(clippy::redundant_closure)] #![allow(dead_code)] #![allow(unused_must_use)] diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs index 7aba5b447d5..61793e80c98 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.rs +++ b/src/tools/clippy/tests/ui/match_same_arms2.rs @@ -1,5 +1,5 @@ #![warn(clippy::match_same_arms)] -#![allow(clippy::blacklisted_name, clippy::diverging_sub_expression)] +#![allow(clippy::disallowed_names, clippy::diverging_sub_expression)] fn bar<T>(_: T) {} fn foo() -> bool { diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs index 1970c2eae53..6f22366eab2 100644 --- a/src/tools/clippy/tests/ui/methods.rs +++ b/src/tools/clippy/tests/ui/methods.rs @@ -2,7 +2,7 @@ #![warn(clippy::all, clippy::pedantic)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_names, clippy::default_trait_access, clippy::missing_docs_in_private_items, clippy::missing_safety_doc, diff --git a/src/tools/clippy/tests/ui/mismatching_type_param_order.rs b/src/tools/clippy/tests/ui/mismatching_type_param_order.rs index 8c0da84d8e9..40c1fcae1fd 100644 --- a/src/tools/clippy/tests/ui/mismatching_type_param_order.rs +++ b/src/tools/clippy/tests/ui/mismatching_type_param_order.rs @@ -1,5 +1,5 @@ #![warn(clippy::mismatching_type_param_order)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] fn main() { struct Foo<A, B> { diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs index aa60d0504e5..b950248ef94 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -3,12 +3,16 @@ //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. // aux-build:helper.rs +// aux-build:../../auxiliary/proc_macro_with_span.rs #![warn(clippy::missing_const_for_fn)] #![feature(start)] #![feature(custom_inner_attributes)] extern crate helper; +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; struct Game; @@ -119,3 +123,8 @@ mod const_fn_stabilized_after_msrv { byte.is_ascii_digit(); } } + +with_span! { + span + fn dont_check_in_proc_macro() {} +} diff --git a/src/tools/clippy/tests/ui/missing-doc.rs b/src/tools/clippy/tests/ui/missing_doc.rs index 6e2e710e21c..29cc026a8fd 100644 --- a/src/tools/clippy/tests/ui/missing-doc.rs +++ b/src/tools/clippy/tests/ui/missing_doc.rs @@ -1,3 +1,5 @@ +// aux-build: proc_macro_with_span.rs + #![warn(clippy::missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the // injected intrinsics by the compiler. @@ -5,6 +7,9 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; use std::arch::global_asm; type Typedef = String; @@ -100,3 +105,11 @@ fn main() {} // Ensure global asm doesn't require documentation. global_asm! { "" } + +// Don't lint proc macro output with an unexpected span. +with_span!(span pub struct FooPm { pub field: u32}); +with_span!(span pub struct FooPm2;); +with_span!(span pub enum FooPm3 { A, B(u32), C { field: u32 }}); +with_span!(span pub fn foo_pm() {}); +with_span!(span pub static FOO_PM: u32 = 0;); +with_span!(span pub const FOO2_PM: u32 = 0;); diff --git a/src/tools/clippy/tests/ui/missing-doc.stderr b/src/tools/clippy/tests/ui/missing_doc.stderr index a876dc078eb..6c8e66f4643 100644 --- a/src/tools/clippy/tests/ui/missing-doc.stderr +++ b/src/tools/clippy/tests/ui/missing_doc.stderr @@ -1,5 +1,5 @@ error: missing documentation for a type alias - --> $DIR/missing-doc.rs:10:1 + --> $DIR/missing_doc.rs:15:1 | LL | type Typedef = String; | ^^^^^^^^^^^^^^^^^^^^^^ @@ -7,37 +7,37 @@ LL | type Typedef = String; = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` error: missing documentation for a type alias - --> $DIR/missing-doc.rs:11:1 + --> $DIR/missing_doc.rs:16:1 | LL | pub type PubTypedef = String; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:13:1 + --> $DIR/missing_doc.rs:18:1 | LL | mod module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:14:1 + --> $DIR/missing_doc.rs:19:1 | LL | pub mod pub_module_no_dox {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:18:1 + --> $DIR/missing_doc.rs:23:1 | LL | pub fn foo2() {} | ^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:19:1 + --> $DIR/missing_doc.rs:24:1 | LL | fn foo3() {} | ^^^^^^^^^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:33:1 + --> $DIR/missing_doc.rs:38:1 | LL | / enum Baz { LL | | BazA { a: isize, b: isize }, @@ -46,31 +46,31 @@ LL | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:34:5 + --> $DIR/missing_doc.rs:39:5 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:34:12 + --> $DIR/missing_doc.rs:39:12 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:34:22 + --> $DIR/missing_doc.rs:39:22 | LL | BazA { a: isize, b: isize }, | ^^^^^^^^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:35:5 + --> $DIR/missing_doc.rs:40:5 | LL | BarB, | ^^^^ error: missing documentation for an enum - --> $DIR/missing-doc.rs:38:1 + --> $DIR/missing_doc.rs:43:1 | LL | / pub enum PubBaz { LL | | PubBazA { a: isize }, @@ -78,43 +78,43 @@ LL | | } | |_^ error: missing documentation for a variant - --> $DIR/missing-doc.rs:39:5 + --> $DIR/missing_doc.rs:44:5 | LL | PubBazA { a: isize }, | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc.rs:39:15 + --> $DIR/missing_doc.rs:44:15 | LL | PubBazA { a: isize }, | ^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:59:1 + --> $DIR/missing_doc.rs:64:1 | LL | const FOO: u32 = 0; | ^^^^^^^^^^^^^^^^^^^ error: missing documentation for a constant - --> $DIR/missing-doc.rs:66:1 + --> $DIR/missing_doc.rs:71:1 | LL | pub const FOO4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:68:1 + --> $DIR/missing_doc.rs:73:1 | LL | static BAR: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a static - --> $DIR/missing-doc.rs:75:1 + --> $DIR/missing_doc.rs:80:1 | LL | pub static BAR4: u32 = 0; | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a module - --> $DIR/missing-doc.rs:77:1 + --> $DIR/missing_doc.rs:82:1 | LL | / mod internal_impl { LL | | /// dox @@ -126,31 +126,31 @@ LL | | } | |_^ error: missing documentation for a function - --> $DIR/missing-doc.rs:80:5 + --> $DIR/missing_doc.rs:85:5 | LL | pub fn undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:81:5 + --> $DIR/missing_doc.rs:86:5 | LL | pub fn undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:82:5 + --> $DIR/missing_doc.rs:87:5 | LL | fn undocumented3() {} | ^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:87:9 + --> $DIR/missing_doc.rs:92:9 | LL | pub fn also_undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for a function - --> $DIR/missing-doc.rs:88:9 + --> $DIR/missing_doc.rs:93:9 | LL | fn also_undocumented2() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/missing-doc-crate.rs b/src/tools/clippy/tests/ui/missing_doc_crate.rs index e00c7fbfed1..e00c7fbfed1 100644 --- a/src/tools/clippy/tests/ui/missing-doc-crate.rs +++ b/src/tools/clippy/tests/ui/missing_doc_crate.rs diff --git a/src/tools/clippy/tests/ui/missing-doc-crate-missing.rs b/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs index 51fd57df8df..51fd57df8df 100644 --- a/src/tools/clippy/tests/ui/missing-doc-crate-missing.rs +++ b/src/tools/clippy/tests/ui/missing_doc_crate_missing.rs diff --git a/src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr b/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr index d56c5cc4c3a..19516bf5fab 100644 --- a/src/tools/clippy/tests/ui/missing-doc-crate-missing.stderr +++ b/src/tools/clippy/tests/ui/missing_doc_crate_missing.stderr @@ -1,5 +1,5 @@ error: missing documentation for the crate - --> $DIR/missing-doc-crate-missing.rs:1:1 + --> $DIR/missing_doc_crate_missing.rs:1:1 | LL | / #![warn(clippy::missing_docs_in_private_items)] LL | | diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.rs b/src/tools/clippy/tests/ui/missing_doc_impl.rs index d5724bf661c..0396d1193ff 100644 --- a/src/tools/clippy/tests/ui/missing-doc-impl.rs +++ b/src/tools/clippy/tests/ui/missing_doc_impl.rs @@ -1,3 +1,5 @@ +// aux-build: proc_macro_with_span.rs + #![warn(clippy::missing_docs_in_private_items)] #![allow(dead_code)] #![feature(associated_type_defaults)] @@ -5,6 +7,9 @@ //! Some garbage docs for the crate here #![doc = "More garbage"] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + struct Foo { a: isize, b: isize, @@ -90,3 +95,13 @@ impl F for Foo { } fn main() {} + +// don't lint proc macro output +with_span!(span + pub struct FooPm; + impl FooPm { + pub fn foo() {} + pub const fn bar() {} + pub const X: u32 = 0; + } +); diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.stderr b/src/tools/clippy/tests/ui/missing_doc_impl.stderr index bda63d66a17..f22fa19dbca 100644 --- a/src/tools/clippy/tests/ui/missing-doc-impl.stderr +++ b/src/tools/clippy/tests/ui/missing_doc_impl.stderr @@ -1,5 +1,5 @@ error: missing documentation for a struct - --> $DIR/missing-doc-impl.rs:8:1 + --> $DIR/missing_doc_impl.rs:13:1 | LL | / struct Foo { LL | | a: isize, @@ -10,19 +10,19 @@ LL | | } = note: `-D clippy::missing-docs-in-private-items` implied by `-D warnings` error: missing documentation for a struct field - --> $DIR/missing-doc-impl.rs:9:5 + --> $DIR/missing_doc_impl.rs:14:5 | LL | a: isize, | ^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc-impl.rs:10:5 + --> $DIR/missing_doc_impl.rs:15:5 | LL | b: isize, | ^^^^^^^^ error: missing documentation for a struct - --> $DIR/missing-doc-impl.rs:13:1 + --> $DIR/missing_doc_impl.rs:18:1 | LL | / pub struct PubFoo { LL | | pub a: isize, @@ -31,19 +31,19 @@ LL | | } | |_^ error: missing documentation for a struct field - --> $DIR/missing-doc-impl.rs:14:5 + --> $DIR/missing_doc_impl.rs:19:5 | LL | pub a: isize, | ^^^^^^^^^^^^ error: missing documentation for a struct field - --> $DIR/missing-doc-impl.rs:15:5 + --> $DIR/missing_doc_impl.rs:20:5 | LL | b: isize, | ^^^^^^^^ error: missing documentation for a trait - --> $DIR/missing-doc-impl.rs:38:1 + --> $DIR/missing_doc_impl.rs:43:1 | LL | / pub trait C { LL | | fn foo(&self); @@ -52,31 +52,31 @@ LL | | } | |_^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:39:5 + --> $DIR/missing_doc_impl.rs:44:5 | LL | fn foo(&self); | ^^^^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:40:5 + --> $DIR/missing_doc_impl.rs:45:5 | LL | fn foo_with_impl(&self) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type - --> $DIR/missing-doc-impl.rs:50:5 + --> $DIR/missing_doc_impl.rs:55:5 | LL | type AssociatedType; | ^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated type - --> $DIR/missing-doc-impl.rs:51:5 + --> $DIR/missing_doc_impl.rs:56:5 | LL | type AssociatedTypeDef = Self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:62:5 + --> $DIR/missing_doc_impl.rs:67:5 | LL | / pub fn new() -> Self { LL | | Foo { a: 0, b: 0 } @@ -84,19 +84,19 @@ LL | | } | |_____^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:65:5 + --> $DIR/missing_doc_impl.rs:70:5 | LL | fn bar() {} | ^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:69:5 + --> $DIR/missing_doc_impl.rs:74:5 | LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:73:5 + --> $DIR/missing_doc_impl.rs:78:5 | LL | / fn foo2() -> u32 { LL | | 1 diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed index a7b36d53cd2..becb9562a84 100644 --- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed +++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![allow( dead_code, @@ -9,6 +10,9 @@ clippy::unusual_byte_groupings )] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + fn main() { let fail14 = 2_i32; let fail15 = 4_i64; @@ -40,4 +44,6 @@ fn main() { let ok38 = 124_64.0; let _ = 1.123_45E1_f32; + + let _ = with_span!(1 2_u32); } diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs index c97b31965c7..ee841bcd7e4 100644 --- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs +++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs @@ -1,4 +1,5 @@ // run-rustfix +// aux-build: proc_macro_with_span.rs #![allow( dead_code, @@ -9,6 +10,9 @@ clippy::unusual_byte_groupings )] +extern crate proc_macro_with_span; +use proc_macro_with_span::with_span; + fn main() { let fail14 = 2_32; let fail15 = 4_64; @@ -40,4 +44,6 @@ fn main() { let ok38 = 124_64.0; let _ = 1.12345E1_32; + + let _ = with_span!(1 2_u32); } diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr index fb761d9bde4..ef8e6a33d28 100644 --- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr +++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.stderr @@ -1,5 +1,5 @@ error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:13:18 + --> $DIR/mistyped_literal_suffix.rs:17:18 | LL | let fail14 = 2_32; | ^^^^ help: did you mean to write: `2_i32` @@ -7,91 +7,91 @@ LL | let fail14 = 2_32; = note: `#[deny(clippy::mistyped_literal_suffixes)]` on by default error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:14:18 + --> $DIR/mistyped_literal_suffix.rs:18:18 | LL | let fail15 = 4_64; | ^^^^ help: did you mean to write: `4_i64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:15:18 + --> $DIR/mistyped_literal_suffix.rs:19:18 | LL | let fail16 = 7_8; // | ^^^ help: did you mean to write: `7_i8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:16:18 + --> $DIR/mistyped_literal_suffix.rs:20:18 | LL | let fail17 = 23_16; // | ^^^^^ help: did you mean to write: `23_i16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:19:18 + --> $DIR/mistyped_literal_suffix.rs:23:18 | LL | let fail20 = 2__8; // | ^^^^ help: did you mean to write: `2_i8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:20:18 + --> $DIR/mistyped_literal_suffix.rs:24:18 | LL | let fail21 = 4___16; // | ^^^^^^ help: did you mean to write: `4_i16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:23:18 + --> $DIR/mistyped_literal_suffix.rs:27:18 | LL | let fail25 = 1E2_32; | ^^^^^^ help: did you mean to write: `1E2_f32` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:24:18 + --> $DIR/mistyped_literal_suffix.rs:28:18 | LL | let fail26 = 43E7_64; | ^^^^^^^ help: did you mean to write: `43E7_f64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:25:18 + --> $DIR/mistyped_literal_suffix.rs:29:18 | LL | let fail27 = 243E17_32; | ^^^^^^^^^ help: did you mean to write: `243E17_f32` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:26:18 + --> $DIR/mistyped_literal_suffix.rs:30:18 | LL | let fail28 = 241251235E723_64; | ^^^^^^^^^^^^^^^^ help: did you mean to write: `241_251_235E723_f64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:30:18 + --> $DIR/mistyped_literal_suffix.rs:34:18 | LL | let fail30 = 127_8; // should be i8 | ^^^^^ help: did you mean to write: `127_i8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:31:18 + --> $DIR/mistyped_literal_suffix.rs:35:18 | LL | let fail31 = 240_8; // should be u8 | ^^^^^ help: did you mean to write: `240_u8` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:33:18 + --> $DIR/mistyped_literal_suffix.rs:37:18 | LL | let fail33 = 0x1234_16; | ^^^^^^^^^ help: did you mean to write: `0x1234_i16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:34:18 + --> $DIR/mistyped_literal_suffix.rs:38:18 | LL | let fail34 = 0xABCD_16; | ^^^^^^^^^ help: did you mean to write: `0xABCD_u16` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:36:18 + --> $DIR/mistyped_literal_suffix.rs:40:18 | LL | let fail36 = 0xFFFF_FFFF_FFFF_FFFF_64; // u64 | ^^^^^^^^^^^^^^^^^^^^^^^^ help: did you mean to write: `0xFFFF_FFFF_FFFF_FFFF_u64` error: mistyped literal suffix - --> $DIR/mistyped_literal_suffix.rs:42:13 + --> $DIR/mistyped_literal_suffix.rs:46:13 | LL | let _ = 1.12345E1_32; | ^^^^^^^^^^^^ help: did you mean to write: `1.123_45E1_f32` diff --git a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs index 7640057ab6e..6efc7657ec0 100644 --- a/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs +++ b/src/tools/clippy/tests/ui/mixed_read_write_in_expression.rs @@ -4,7 +4,7 @@ unused_variables, clippy::no_effect, dead_code, - clippy::blacklisted_name + clippy::disallowed_names )] fn main() { let mut x = 0; diff --git a/src/tools/clippy/tests/ui/op_ref.rs b/src/tools/clippy/tests/ui/op_ref.rs index d8bf66603d9..07226b0a1a8 100644 --- a/src/tools/clippy/tests/ui/op_ref.rs +++ b/src/tools/clippy/tests/ui/op_ref.rs @@ -1,4 +1,4 @@ -#![allow(unused_variables, clippy::blacklisted_name)] +#![allow(unused_variables, clippy::disallowed_names)] #![warn(clippy::op_ref)] use std::collections::HashSet; use std::ops::{BitAnd, Mul}; diff --git a/src/tools/clippy/tests/ui/logic_bug.rs b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs index dd6b1db5f70..04a30a83250 100644 --- a/src/tools/clippy/tests/ui/logic_bug.rs +++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.rs @@ -1,6 +1,6 @@ #![feature(lint_reasons)] #![allow(unused, clippy::diverging_sub_expression)] -#![warn(clippy::logic_bug)] +#![warn(clippy::overly_complex_bool_expr)] fn main() { let a: bool = unimplemented!(); @@ -29,6 +29,6 @@ fn equality_stuff() { fn check_expect() { let a: i32 = unimplemented!(); let b: i32 = unimplemented!(); - #[expect(clippy::logic_bug)] + #[expect(clippy::overly_complex_bool_expr)] let _ = a < b && a >= b; } diff --git a/src/tools/clippy/tests/ui/logic_bug.stderr b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr index 4021fbf4570..158cae8b8f3 100644 --- a/src/tools/clippy/tests/ui/logic_bug.stderr +++ b/src/tools/clippy/tests/ui/overly_complex_bool_expr.stderr @@ -1,60 +1,60 @@ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:11:13 + --> $DIR/overly_complex_bool_expr.rs:11:13 | LL | let _ = a && b || a; | ^^^^^^^^^^^ help: it would look like the following: `a` | - = note: `-D clippy::logic-bug` implied by `-D warnings` + = note: `-D clippy::overly-complex-bool-expr` implied by `-D warnings` help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:11:18 + --> $DIR/overly_complex_bool_expr.rs:11:18 | LL | let _ = a && b || a; | ^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:13:13 + --> $DIR/overly_complex_bool_expr.rs:13:13 | LL | let _ = false && a; | ^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:13:22 + --> $DIR/overly_complex_bool_expr.rs:13:22 | LL | let _ = false && a; | ^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:23:13 + --> $DIR/overly_complex_bool_expr.rs:23:13 | LL | let _ = a == b && a != b; | ^^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:23:13 + --> $DIR/overly_complex_bool_expr.rs:23:13 | LL | let _ = a == b && a != b; | ^^^^^^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:24:13 + --> $DIR/overly_complex_bool_expr.rs:24:13 | LL | let _ = a < b && a >= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:24:13 + --> $DIR/overly_complex_bool_expr.rs:24:13 | LL | let _ = a < b && a >= b; | ^^^^^ error: this boolean expression contains a logic bug - --> $DIR/logic_bug.rs:25:13 + --> $DIR/overly_complex_bool_expr.rs:25:13 | LL | let _ = a > b && a <= b; | ^^^^^^^^^^^^^^^ help: it would look like the following: `false` | help: this expression can be optimized out by applying boolean operations to the outer expression - --> $DIR/logic_bug.rs:25:13 + --> $DIR/overly_complex_bool_expr.rs:25:13 | LL | let _ = a > b && a <= b; | ^^^^^ diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.fixed b/src/tools/clippy/tests/ui/partialeq_to_none.fixed new file mode 100644 index 00000000000..f3e4c58d694 --- /dev/null +++ b/src/tools/clippy/tests/ui/partialeq_to_none.fixed @@ -0,0 +1,62 @@ +// run-rustfix +#![warn(clippy::partialeq_to_none)] + +struct Foobar; + +impl PartialEq<Option<()>> for Foobar { + fn eq(&self, _: &Option<()>) -> bool { + false + } +} + +#[allow(dead_code)] +fn foo(f: Option<u32>) -> &'static str { + if f.is_some() { "yay" } else { "nay" } +} + +fn foobar() -> Option<()> { + None +} + +fn bar() -> Result<(), ()> { + Ok(()) +} + +fn optref() -> &'static &'static Option<()> { + &&None +} + +fn main() { + let x = Some(0); + + let _ = x.is_none(); + let _ = x.is_some(); + let _ = x.is_none(); + let _ = x.is_some(); + + if foobar().is_none() {} + + if bar().ok().is_some() {} + + let _ = Some(1 + 2).is_some(); + + let _ = { Some(0) }.is_none(); + + let _ = { + /* + This comment runs long + */ + Some(1) + }.is_some(); + + // Should not trigger, as `Foobar` is not an `Option` and has no `is_none` + let _ = Foobar == None; + + let _ = optref().is_none(); + let _ = optref().is_some(); + let _ = optref().is_none(); + let _ = optref().is_some(); + + let x = Box::new(Option::<()>::None); + let _ = (*x).is_some(); +} diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.rs b/src/tools/clippy/tests/ui/partialeq_to_none.rs new file mode 100644 index 00000000000..767b2a38bcc --- /dev/null +++ b/src/tools/clippy/tests/ui/partialeq_to_none.rs @@ -0,0 +1,62 @@ +// run-rustfix +#![warn(clippy::partialeq_to_none)] + +struct Foobar; + +impl PartialEq<Option<()>> for Foobar { + fn eq(&self, _: &Option<()>) -> bool { + false + } +} + +#[allow(dead_code)] +fn foo(f: Option<u32>) -> &'static str { + if f != None { "yay" } else { "nay" } +} + +fn foobar() -> Option<()> { + None +} + +fn bar() -> Result<(), ()> { + Ok(()) +} + +fn optref() -> &'static &'static Option<()> { + &&None +} + +fn main() { + let x = Some(0); + + let _ = x == None; + let _ = x != None; + let _ = None == x; + let _ = None != x; + + if foobar() == None {} + + if bar().ok() != None {} + + let _ = Some(1 + 2) != None; + + let _ = { Some(0) } == None; + + let _ = { + /* + This comment runs long + */ + Some(1) + } != None; + + // Should not trigger, as `Foobar` is not an `Option` and has no `is_none` + let _ = Foobar == None; + + let _ = optref() == &&None; + let _ = &&None != optref(); + let _ = **optref() == None; + let _ = &None != *optref(); + + let x = Box::new(Option::<()>::None); + let _ = None != *x; +} diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.stderr b/src/tools/clippy/tests/ui/partialeq_to_none.stderr new file mode 100644 index 00000000000..de15a9f7baa --- /dev/null +++ b/src/tools/clippy/tests/ui/partialeq_to_none.stderr @@ -0,0 +1,110 @@ +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:14:8 + | +LL | if f != None { "yay" } else { "nay" } + | ^^^^^^^^^ help: use `Option::is_some()` instead: `f.is_some()` + | + = note: `-D clippy::partialeq-to-none` implied by `-D warnings` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:32:13 + | +LL | let _ = x == None; + | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:33:13 + | +LL | let _ = x != None; + | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:34:13 + | +LL | let _ = None == x; + | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:35:13 + | +LL | let _ = None != x; + | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:37:8 + | +LL | if foobar() == None {} + | ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:39:8 + | +LL | if bar().ok() != None {} + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:41:13 + | +LL | let _ = Some(1 + 2) != None; + | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:43:13 + | +LL | let _ = { Some(0) } == None; + | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:45:13 + | +LL | let _ = { + | _____________^ +LL | | /* +LL | | This comment runs long +LL | | */ +LL | | Some(1) +LL | | } != None; + | |_____________^ + | +help: use `Option::is_some()` instead + | +LL ~ let _ = { +LL + /* +LL + This comment runs long +LL + */ +LL + Some(1) +LL ~ }.is_some(); + | + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:55:13 + | +LL | let _ = optref() == &&None; + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:56:13 + | +LL | let _ = &&None != optref(); + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:57:13 + | +LL | let _ = **optref() == None; + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:58:13 + | +LL | let _ = &None != *optref(); + | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` + +error: binary comparison to literal `Option::None` + --> $DIR/partialeq_to_none.rs:61:13 + | +LL | let _ = None != *x; + | ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()` + +error: aborting due to 15 previous errors + diff --git a/src/tools/clippy/tests/ui/rc_mutex.rs b/src/tools/clippy/tests/ui/rc_mutex.rs index 18e8a2e01e0..432972bbc31 100644 --- a/src/tools/clippy/tests/ui/rc_mutex.rs +++ b/src/tools/clippy/tests/ui/rc_mutex.rs @@ -1,5 +1,5 @@ #![warn(clippy::rc_mutex)] -#![allow(unused, clippy::blacklisted_name)] +#![allow(unused, clippy::disallowed_names)] use std::rc::Rc; use std::sync::Mutex; diff --git a/src/tools/clippy/tests/ui/redundant_allocation.rs b/src/tools/clippy/tests/ui/redundant_allocation.rs index cf7d8c6e349..574d34aed2d 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation.rs +++ b/src/tools/clippy/tests/ui/redundant_allocation.rs @@ -1,7 +1,5 @@ #![warn(clippy::all)] -#![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::blacklisted_name, unused_variables, dead_code)] -#![allow(unused_imports)] +#![allow(clippy::boxed_local, clippy::disallowed_names)] pub struct MyStruct; @@ -9,13 +7,7 @@ pub struct SubT<T> { foo: T, } -pub enum MyEnum { - One, - Two, -} - mod outer_box { - use crate::MyEnum; use crate::MyStruct; use crate::SubT; use std::boxed::Box; @@ -36,7 +28,6 @@ mod outer_box { } mod outer_rc { - use crate::MyEnum; use crate::MyStruct; use crate::SubT; use std::boxed::Box; @@ -57,7 +48,6 @@ mod outer_rc { } mod outer_arc { - use crate::MyEnum; use crate::MyStruct; use crate::SubT; use std::boxed::Box; diff --git a/src/tools/clippy/tests/ui/redundant_allocation.stderr b/src/tools/clippy/tests/ui/redundant_allocation.stderr index fab1b069fcb..54d4d88dba8 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation.stderr +++ b/src/tools/clippy/tests/ui/redundant_allocation.stderr @@ -1,5 +1,5 @@ error: usage of `Box<Rc<T>>` - --> $DIR/redundant_allocation.rs:25:30 + --> $DIR/redundant_allocation.rs:17:30 | LL | pub fn box_test6<T>(foo: Box<Rc<T>>) {} | ^^^^^^^^^^ @@ -9,7 +9,7 @@ LL | pub fn box_test6<T>(foo: Box<Rc<T>>) {} = help: consider using just `Box<T>` or `Rc<T>` error: usage of `Box<Arc<T>>` - --> $DIR/redundant_allocation.rs:27:30 + --> $DIR/redundant_allocation.rs:19:30 | LL | pub fn box_test7<T>(foo: Box<Arc<T>>) {} | ^^^^^^^^^^^ @@ -18,7 +18,7 @@ LL | pub fn box_test7<T>(foo: Box<Arc<T>>) {} = help: consider using just `Box<T>` or `Arc<T>` error: usage of `Box<Rc<SubT<usize>>>` - --> $DIR/redundant_allocation.rs:29:27 + --> $DIR/redundant_allocation.rs:21:27 | LL | pub fn box_test8() -> Box<Rc<SubT<usize>>> { | ^^^^^^^^^^^^^^^^^^^^ @@ -27,7 +27,7 @@ LL | pub fn box_test8() -> Box<Rc<SubT<usize>>> { = help: consider using just `Box<SubT<usize>>` or `Rc<SubT<usize>>` error: usage of `Box<Arc<T>>` - --> $DIR/redundant_allocation.rs:33:30 + --> $DIR/redundant_allocation.rs:25:30 | LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> { | ^^^^^^^^^^^ @@ -36,7 +36,7 @@ LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> { = help: consider using just `Box<T>` or `Arc<T>` error: usage of `Box<Arc<SubT<T>>>` - --> $DIR/redundant_allocation.rs:33:46 + --> $DIR/redundant_allocation.rs:25:46 | LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> { | ^^^^^^^^^^^^^^^^^ @@ -45,7 +45,7 @@ LL | pub fn box_test9<T>(foo: Box<Arc<T>>) -> Box<Arc<SubT<T>>> { = help: consider using just `Box<SubT<T>>` or `Arc<SubT<T>>` error: usage of `Rc<Box<bool>>` - --> $DIR/redundant_allocation.rs:46:24 + --> $DIR/redundant_allocation.rs:37:24 | LL | pub fn rc_test5(a: Rc<Box<bool>>) {} | ^^^^^^^^^^^^^ @@ -54,7 +54,7 @@ LL | pub fn rc_test5(a: Rc<Box<bool>>) {} = help: consider using just `Rc<bool>` or `Box<bool>` error: usage of `Rc<Arc<bool>>` - --> $DIR/redundant_allocation.rs:48:24 + --> $DIR/redundant_allocation.rs:39:24 | LL | pub fn rc_test7(a: Rc<Arc<bool>>) {} | ^^^^^^^^^^^^^ @@ -63,7 +63,7 @@ LL | pub fn rc_test7(a: Rc<Arc<bool>>) {} = help: consider using just `Rc<bool>` or `Arc<bool>` error: usage of `Rc<Box<SubT<usize>>>` - --> $DIR/redundant_allocation.rs:50:26 + --> $DIR/redundant_allocation.rs:41:26 | LL | pub fn rc_test8() -> Rc<Box<SubT<usize>>> { | ^^^^^^^^^^^^^^^^^^^^ @@ -72,7 +72,7 @@ LL | pub fn rc_test8() -> Rc<Box<SubT<usize>>> { = help: consider using just `Rc<SubT<usize>>` or `Box<SubT<usize>>` error: usage of `Rc<Arc<T>>` - --> $DIR/redundant_allocation.rs:54:29 + --> $DIR/redundant_allocation.rs:45:29 | LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> { | ^^^^^^^^^^ @@ -81,7 +81,7 @@ LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> { = help: consider using just `Rc<T>` or `Arc<T>` error: usage of `Rc<Arc<SubT<T>>>` - --> $DIR/redundant_allocation.rs:54:44 + --> $DIR/redundant_allocation.rs:45:44 | LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> { | ^^^^^^^^^^^^^^^^ @@ -90,7 +90,7 @@ LL | pub fn rc_test9<T>(foo: Rc<Arc<T>>) -> Rc<Arc<SubT<T>>> { = help: consider using just `Rc<SubT<T>>` or `Arc<SubT<T>>` error: usage of `Arc<Box<bool>>` - --> $DIR/redundant_allocation.rs:67:25 + --> $DIR/redundant_allocation.rs:57:25 | LL | pub fn arc_test5(a: Arc<Box<bool>>) {} | ^^^^^^^^^^^^^^ @@ -99,7 +99,7 @@ LL | pub fn arc_test5(a: Arc<Box<bool>>) {} = help: consider using just `Arc<bool>` or `Box<bool>` error: usage of `Arc<Rc<bool>>` - --> $DIR/redundant_allocation.rs:69:25 + --> $DIR/redundant_allocation.rs:59:25 | LL | pub fn arc_test6(a: Arc<Rc<bool>>) {} | ^^^^^^^^^^^^^ @@ -108,7 +108,7 @@ LL | pub fn arc_test6(a: Arc<Rc<bool>>) {} = help: consider using just `Arc<bool>` or `Rc<bool>` error: usage of `Arc<Box<SubT<usize>>>` - --> $DIR/redundant_allocation.rs:71:27 + --> $DIR/redundant_allocation.rs:61:27 | LL | pub fn arc_test8() -> Arc<Box<SubT<usize>>> { | ^^^^^^^^^^^^^^^^^^^^^ @@ -117,7 +117,7 @@ LL | pub fn arc_test8() -> Arc<Box<SubT<usize>>> { = help: consider using just `Arc<SubT<usize>>` or `Box<SubT<usize>>` error: usage of `Arc<Rc<T>>` - --> $DIR/redundant_allocation.rs:75:30 + --> $DIR/redundant_allocation.rs:65:30 | LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> { | ^^^^^^^^^^ @@ -126,7 +126,7 @@ LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> { = help: consider using just `Arc<T>` or `Rc<T>` error: usage of `Arc<Rc<SubT<T>>>` - --> $DIR/redundant_allocation.rs:75:45 + --> $DIR/redundant_allocation.rs:65:45 | LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> { | ^^^^^^^^^^^^^^^^ @@ -135,7 +135,7 @@ LL | pub fn arc_test9<T>(foo: Arc<Rc<T>>) -> Arc<Rc<SubT<T>>> { = help: consider using just `Arc<SubT<T>>` or `Rc<SubT<T>>` error: usage of `Rc<Box<Box<dyn T>>>` - --> $DIR/redundant_allocation.rs:97:27 + --> $DIR/redundant_allocation.rs:87:27 | LL | pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {} | ^^^^^^^^^^^^^^^^^^^ @@ -144,7 +144,7 @@ LL | pub fn test_rc_box(_: Rc<Box<Box<dyn T>>>) {} = help: consider using just `Rc<Box<dyn T>>` or `Box<Box<dyn T>>` error: usage of `Rc<Box<Box<str>>>` - --> $DIR/redundant_allocation.rs:129:31 + --> $DIR/redundant_allocation.rs:119:31 | LL | pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {} | ^^^^^^^^^^^^^^^^^ @@ -153,7 +153,7 @@ LL | pub fn test_rc_box_str(_: Rc<Box<Box<str>>>) {} = help: consider using just `Rc<Box<str>>` or `Box<Box<str>>` error: usage of `Rc<Box<Box<[usize]>>>` - --> $DIR/redundant_allocation.rs:130:33 + --> $DIR/redundant_allocation.rs:120:33 | LL | pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {} | ^^^^^^^^^^^^^^^^^^^^^ @@ -162,7 +162,7 @@ LL | pub fn test_rc_box_slice(_: Rc<Box<Box<[usize]>>>) {} = help: consider using just `Rc<Box<[usize]>>` or `Box<Box<[usize]>>` error: usage of `Rc<Box<Box<Path>>>` - --> $DIR/redundant_allocation.rs:131:32 + --> $DIR/redundant_allocation.rs:121:32 | LL | pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {} | ^^^^^^^^^^^^^^^^^^ @@ -171,7 +171,7 @@ LL | pub fn test_rc_box_path(_: Rc<Box<Box<Path>>>) {} = help: consider using just `Rc<Box<Path>>` or `Box<Box<Path>>` error: usage of `Rc<Box<Box<DynSized>>>` - --> $DIR/redundant_allocation.rs:132:34 + --> $DIR/redundant_allocation.rs:122:34 | LL | pub fn test_rc_box_custom(_: Rc<Box<Box<DynSized>>>) {} | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed index e7ed84731c0..6db02718c70 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed +++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::blacklisted_name, unused_variables, dead_code)] +#![allow(clippy::disallowed_names, unused_variables, dead_code)] #![allow(unused_imports)] pub struct MyStruct; diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs index de763f98b5c..c15806f30c0 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs +++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] -#![allow(clippy::blacklisted_name, unused_variables, dead_code)] +#![allow(clippy::disallowed_names, unused_variables, dead_code)] #![allow(unused_imports)] pub struct MyStruct; diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed index 0abca6fca06..7cd687c95a0 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed @@ -1,8 +1,28 @@ // run-rustfix +#![feature(async_closure)] #![warn(clippy::redundant_closure_call)] #![allow(unused)] +async fn something() -> u32 { + 21 +} + +async fn something_else() -> u32 { + 2 +} + fn main() { let a = 42; + let b = async { + let x = something().await; + let y = something_else().await; + x * y + }; + let c = { + let x = 21; + let y = 2; + x * y + }; + let d = async { something().await }; } diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs index f8b9d37a5cc..37e4d223864 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs @@ -1,8 +1,28 @@ // run-rustfix +#![feature(async_closure)] #![warn(clippy::redundant_closure_call)] #![allow(unused)] +async fn something() -> u32 { + 21 +} + +async fn something_else() -> u32 { + 2 +} + fn main() { let a = (|| 42)(); + let b = (async || { + let x = something().await; + let y = something_else().await; + x * y + })(); + let c = (|| { + let x = 21; + let y = 2; + x * y + })(); + let d = (async || something().await)(); } diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr index afd704ef12a..56a8e57c0c3 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.stderr @@ -1,10 +1,56 @@ error: try not to call a closure in the expression where it is declared - --> $DIR/redundant_closure_call_fixable.rs:7:13 + --> $DIR/redundant_closure_call_fixable.rs:16:13 | LL | let a = (|| 42)(); | ^^^^^^^^^ help: try doing something like: `42` | = note: `-D clippy::redundant-closure-call` implied by `-D warnings` -error: aborting due to previous error +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:17:13 + | +LL | let b = (async || { + | _____________^ +LL | | let x = something().await; +LL | | let y = something_else().await; +LL | | x * y +LL | | })(); + | |________^ + | +help: try doing something like + | +LL ~ let b = async { +LL + let x = something().await; +LL + let y = something_else().await; +LL + x * y +LL ~ }; + | + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:22:13 + | +LL | let c = (|| { + | _____________^ +LL | | let x = 21; +LL | | let y = 2; +LL | | x * y +LL | | })(); + | |________^ + | +help: try doing something like + | +LL ~ let c = { +LL + let x = 21; +LL + let y = 2; +LL + x * y +LL ~ }; + | + +error: try not to call a closure in the expression where it is declared + --> $DIR/redundant_closure_call_fixable.rs:27:13 + | +LL | let d = (async || something().await)(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try doing something like: `async { something().await }` + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index 53288be9404..9cbad2269a0 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -4,6 +4,7 @@ // run-rustfix +#![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] #![allow(clippy::redundant_static_lifetimes)] @@ -14,6 +15,7 @@ #![allow(clippy::for_loops_over_fallibles)] #![allow(clippy::useless_conversion)] #![allow(clippy::match_result_ok)] +#![allow(clippy::overly_complex_bool_expr)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::expect_used)] @@ -33,6 +35,7 @@ #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![warn(clippy::disallowed_names)] #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::blocks_in_if_conditions)] #![warn(clippy::box_collection)] @@ -45,6 +48,7 @@ #![warn(clippy::for_loops_over_fallibles)] #![warn(clippy::useless_conversion)] #![warn(clippy::match_result_ok)] +#![warn(clippy::overly_complex_bool_expr)] #![warn(clippy::new_without_default)] #![warn(clippy::bind_instead_of_map)] #![warn(clippy::expect_used)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index 539f34f847a..9153c0dab02 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -4,6 +4,7 @@ // run-rustfix +#![allow(clippy::disallowed_names)] #![allow(clippy::blocks_in_if_conditions)] #![allow(clippy::box_collection)] #![allow(clippy::redundant_static_lifetimes)] @@ -14,6 +15,7 @@ #![allow(clippy::for_loops_over_fallibles)] #![allow(clippy::useless_conversion)] #![allow(clippy::match_result_ok)] +#![allow(clippy::overly_complex_bool_expr)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] #![allow(clippy::expect_used)] @@ -33,6 +35,7 @@ #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] +#![warn(clippy::blacklisted_name)] #![warn(clippy::block_in_if_condition_expr)] #![warn(clippy::block_in_if_condition_stmt)] #![warn(clippy::box_vec)] @@ -45,6 +48,7 @@ #![warn(clippy::for_loop_over_result)] #![warn(clippy::identity_conversion)] #![warn(clippy::if_let_some_result)] +#![warn(clippy::logic_bug)] #![warn(clippy::new_without_default_derive)] #![warn(clippy::option_and_then_some)] #![warn(clippy::option_expect_used)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 8ea46b580a8..9c03ea914bb 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,214 +1,226 @@ +error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` + --> $DIR/rename.rs:38:9 + | +LL | #![warn(clippy::blacklisted_name)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` + | + = note: `-D renamed-and-removed-lints` implied by `-D warnings` + error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:36:9 + --> $DIR/rename.rs:39:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` - | - = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:37:9 + --> $DIR/rename.rs:40:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:38:9 + --> $DIR/rename.rs:41:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:39:9 + --> $DIR/rename.rs:42:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:40:9 + --> $DIR/rename.rs:43:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:41:9 + --> $DIR/rename.rs:44:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:45:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:46:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::for_loop_over_option` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:47:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `clippy::for_loops_over_fallibles` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:48:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::for_loops_over_fallibles` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` +error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` + --> $DIR/rename.rs:51:9 + | +LL | #![warn(clippy::logic_bug)] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` + error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:62:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 35 previous errors +error: aborting due to 37 previous errors diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs index 3d2295912c9..a48829caac0 100644 --- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs +++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs @@ -48,9 +48,9 @@ fn ifs_same_cond_fn() { } let mut v = vec![1]; - if v.pop() == None { + if v.pop().is_none() { //~ ERROR ifs same condition - } else if v.pop() == None { + } else if v.pop().is_none() { } if v.len() == 42 { diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr index 71e82910ef7..cd438b83040 100644 --- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr +++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr @@ -50,14 +50,14 @@ LL | if obj.method_arg(a) { error: this `if` has the same function call as a previous `if` --> $DIR/same_functions_in_if_condition.rs:53:15 | -LL | } else if v.pop() == None { - | ^^^^^^^^^^^^^^^ +LL | } else if v.pop().is_none() { + | ^^^^^^^^^^^^^^^^^ | note: same as this --> $DIR/same_functions_in_if_condition.rs:51:8 | -LL | if v.pop() == None { - | ^^^^^^^^^^^^^^^ +LL | if v.pop().is_none() { + | ^^^^^^^^^^^^^^^^^ error: this `if` has the same function call as a previous `if` --> $DIR/same_functions_in_if_condition.rs:58:15 diff --git a/src/tools/clippy/tests/ui/skip_while_next.rs b/src/tools/clippy/tests/ui/skip_while_next.rs index a522c0f08b2..a551c19d98b 100644 --- a/src/tools/clippy/tests/ui/skip_while_next.rs +++ b/src/tools/clippy/tests/ui/skip_while_next.rs @@ -1,7 +1,7 @@ // aux-build:option_helpers.rs #![warn(clippy::skip_while_next)] -#![allow(clippy::blacklisted_name)] +#![allow(clippy::disallowed_names)] extern crate option_helpers; use option_helpers::IteratorFalsePositives; diff --git a/src/tools/clippy/tests/ui/swap.fixed b/src/tools/clippy/tests/ui/swap.fixed index 3329efbd4ff..24b229235d3 100644 --- a/src/tools/clippy/tests/ui/swap.fixed +++ b/src/tools/clippy/tests/ui/swap.fixed @@ -2,7 +2,7 @@ #![warn(clippy::all)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_names, clippy::no_effect, clippy::redundant_clone, redundant_semicolons, diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs index 8179ac1f2ab..a318c27919c 100644 --- a/src/tools/clippy/tests/ui/swap.rs +++ b/src/tools/clippy/tests/ui/swap.rs @@ -2,7 +2,7 @@ #![warn(clippy::all)] #![allow( - clippy::blacklisted_name, + clippy::disallowed_names, clippy::no_effect, clippy::redundant_clone, redundant_semicolons, diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs index 8f78f16a0a1..c0c64ebcabf 100644 --- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs +++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs @@ -2,7 +2,7 @@ // normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] -#![allow(clippy::blacklisted_name, clippy::redundant_field_names)] +#![allow(clippy::disallowed_names, clippy::redundant_field_names)] #[derive(Copy, Clone)] struct Foo(u32); diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs index 38be87bddf1..7bf3adc07ac 100644 --- a/src/tools/clippy/tests/ui/unit_arg.rs +++ b/src/tools/clippy/tests/ui/unit_arg.rs @@ -1,3 +1,5 @@ +// aux-build: proc_macro_with_span.rs + #![warn(clippy::unit_arg)] #![allow( clippy::no_effect, @@ -8,9 +10,13 @@ clippy::or_fun_call, clippy::needless_question_mark, clippy::self_named_constructors, - clippy::let_unit_value + clippy::let_unit_value, + clippy::never_loop )] +extern crate proc_macro_with_span; + +use proc_macro_with_span::with_span; use std::fmt::Debug; fn foo<T: Debug>(t: T) { @@ -127,6 +133,10 @@ fn returning_expr() -> Option<()> { fn taking_multiple_units(a: (), b: ()) {} +fn proc_macro() { + with_span!(span taking_multiple_units(unsafe { (); }, 'x: loop { break 'x (); })); +} + fn main() { bad(); ok(); diff --git a/src/tools/clippy/tests/ui/unit_arg.stderr b/src/tools/clippy/tests/ui/unit_arg.stderr index 11cfe66a30e..1de9d44bb0d 100644 --- a/src/tools/clippy/tests/ui/unit_arg.stderr +++ b/src/tools/clippy/tests/ui/unit_arg.stderr @@ -1,5 +1,5 @@ error: passing a unit value to a function - --> $DIR/unit_arg.rs:57:5 + --> $DIR/unit_arg.rs:63:5 | LL | / foo({ LL | | 1; @@ -20,7 +20,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:60:5 + --> $DIR/unit_arg.rs:66:5 | LL | foo(foo(1)); | ^^^^^^^^^^^ @@ -32,7 +32,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:61:5 + --> $DIR/unit_arg.rs:67:5 | LL | / foo({ LL | | foo(1); @@ -54,7 +54,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:66:5 + --> $DIR/unit_arg.rs:72:5 | LL | / b.bar({ LL | | 1; @@ -74,7 +74,7 @@ LL ~ b.bar(()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:69:5 + --> $DIR/unit_arg.rs:75:5 | LL | taking_multiple_units(foo(0), foo(1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -87,7 +87,7 @@ LL ~ taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:70:5 + --> $DIR/unit_arg.rs:76:5 | LL | / taking_multiple_units(foo(0), { LL | | foo(1); @@ -110,7 +110,7 @@ LL ~ taking_multiple_units((), ()); | error: passing unit values to a function - --> $DIR/unit_arg.rs:74:5 + --> $DIR/unit_arg.rs:80:5 | LL | / taking_multiple_units( LL | | { @@ -146,7 +146,7 @@ LL ~ ); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:85:13 + --> $DIR/unit_arg.rs:91:13 | LL | None.or(Some(foo(2))); | ^^^^^^^^^^^^ @@ -160,7 +160,7 @@ LL ~ }); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:88:5 + --> $DIR/unit_arg.rs:94:5 | LL | foo(foo(())); | ^^^^^^^^^^^^ @@ -172,7 +172,7 @@ LL ~ foo(()); | error: passing a unit value to a function - --> $DIR/unit_arg.rs:125:5 + --> $DIR/unit_arg.rs:131:5 | LL | Some(foo(1)) | ^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.rs b/src/tools/clippy/tests/ui/unwrap_expect_used.rs new file mode 100644 index 00000000000..0d4a0504a6e --- /dev/null +++ b/src/tools/clippy/tests/ui/unwrap_expect_used.rs @@ -0,0 +1,10 @@ +#![warn(clippy::unwrap_used, clippy::expect_used)] + +fn main() { + Some(3).unwrap(); + Some(3).expect("Hello world!"); + + let a: Result<i32, i32> = Ok(3); + a.unwrap(); + a.expect("Hello world!"); +} diff --git a/src/tools/clippy/tests/ui/unwrap_expect_used.stderr b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr new file mode 100644 index 00000000000..f54bfd617c4 --- /dev/null +++ b/src/tools/clippy/tests/ui/unwrap_expect_used.stderr @@ -0,0 +1,36 @@ +error: used `unwrap()` on `an Option` value + --> $DIR/unwrap_expect_used.rs:4:5 + | +LL | Some(3).unwrap(); + | ^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::unwrap-used` implied by `-D warnings` + = help: if this value is `None`, it will panic + +error: used `expect()` on `an Option` value + --> $DIR/unwrap_expect_used.rs:5:5 + | +LL | Some(3).expect("Hello world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::expect-used` implied by `-D warnings` + = help: if this value is `None`, it will panic + +error: used `unwrap()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:8:5 + | +LL | a.unwrap(); + | ^^^^^^^^^^ + | + = help: if this value is an `Err`, it will panic + +error: used `expect()` on `a Result` value + --> $DIR/unwrap_expect_used.rs:9:5 + | +LL | a.expect("Hello world!"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: if this value is an `Err`, it will panic + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.rs b/src/tools/clippy/tests/ui/used_underscore_binding.rs index d20977d55d2..322083511ac 100644 --- a/src/tools/clippy/tests/ui/used_underscore_binding.rs +++ b/src/tools/clippy/tests/ui/used_underscore_binding.rs @@ -2,7 +2,7 @@ #![feature(rustc_private)] #![warn(clippy::all)] -#![allow(clippy::blacklisted_name, clippy::eq_op)] +#![allow(clippy::disallowed_names, clippy::eq_op)] #![warn(clippy::used_underscore_binding)] #[macro_use] diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 23e49539969..41f97e4326a 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -17,6 +17,7 @@ rustfix = "0.6.0" lazy_static = "1.0" walkdir = "2" glob = "0.3.0" +lazycell = "1.3.0" [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index be81ff881f3..6f17b9e1be9 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -3,9 +3,11 @@ pub use self::Mode::*; use std::ffi::OsString; use std::fmt; use std::path::{Path, PathBuf}; +use std::process::Command; use std::str::FromStr; use crate::util::PathBufExt; +use lazycell::LazyCell; use test::ColorConfig; #[derive(Clone, Copy, PartialEq, Debug)] @@ -371,6 +373,8 @@ pub struct Config { /// Whether to rerun tests even if the inputs are unchanged. pub force_rerun: bool, + + pub target_cfg: LazyCell<TargetCfg>, } impl Config { @@ -380,6 +384,131 @@ impl Config { !self.target.ends_with("-fuchsia") }) } + + fn target_cfg(&self) -> &TargetCfg { + self.target_cfg.borrow_with(|| TargetCfg::new(&self.rustc_path, &self.target)) + } + + pub fn matches_arch(&self, arch: &str) -> bool { + self.target_cfg().arch == arch || + // Shorthand for convenience. The arch for + // asmjs-unknown-emscripten is actually wasm32. + (arch == "asmjs" && self.target.starts_with("asmjs")) || + // Matching all the thumb variants as one can be convenient. + // (thumbv6m, thumbv7em, thumbv7m, etc.) + (arch == "thumb" && self.target.starts_with("thumb")) + } + + pub fn matches_os(&self, os: &str) -> bool { + self.target_cfg().os == os + } + + pub fn matches_env(&self, env: &str) -> bool { + self.target_cfg().env == env + } + + pub fn matches_abi(&self, abi: &str) -> bool { + self.target_cfg().abi == abi + } + + pub fn matches_family(&self, family: &str) -> bool { + self.target_cfg().families.iter().any(|f| f == family) + } + + pub fn is_big_endian(&self) -> bool { + self.target_cfg().endian == Endian::Big + } + + pub fn get_pointer_width(&self) -> u32 { + *&self.target_cfg().pointer_width + } + + pub fn has_asm_support(&self) -> bool { + static ASM_SUPPORTED_ARCHS: &[&str] = &[ + "x86", "x86_64", "arm", "aarch64", "riscv32", + "riscv64", + // These targets require an additional asm_experimental_arch feature. + // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32", + ]; + ASM_SUPPORTED_ARCHS.contains(&self.target_cfg().arch.as_str()) + } +} + +#[derive(Clone, Debug)] +pub struct TargetCfg { + arch: String, + os: String, + env: String, + abi: String, + families: Vec<String>, + pointer_width: u32, + endian: Endian, +} + +#[derive(Eq, PartialEq, Clone, Debug)] +pub enum Endian { + Little, + Big, +} + +impl TargetCfg { + fn new(rustc_path: &Path, target: &str) -> TargetCfg { + let output = match Command::new(rustc_path) + .arg("--print=cfg") + .arg("--target") + .arg(target) + .output() + { + Ok(output) => output, + Err(e) => panic!("error: failed to get cfg info from {:?}: {e}", rustc_path), + }; + if !output.status.success() { + panic!( + "error: failed to get cfg info from {:?}\n--- stdout\n{}\n--- stderr\n{}", + rustc_path, + String::from_utf8(output.stdout).unwrap(), + String::from_utf8(output.stderr).unwrap(), + ); + } + let print_cfg = String::from_utf8(output.stdout).unwrap(); + let mut arch = None; + let mut os = None; + let mut env = None; + let mut abi = None; + let mut families = Vec::new(); + let mut pointer_width = None; + let mut endian = None; + for line in print_cfg.lines() { + if let Some((name, value)) = line.split_once('=') { + let value = value.trim_matches('"'); + match name { + "target_arch" => arch = Some(value), + "target_os" => os = Some(value), + "target_env" => env = Some(value), + "target_abi" => abi = Some(value), + "target_family" => families.push(value.to_string()), + "target_pointer_width" => pointer_width = Some(value.parse().unwrap()), + "target_endian" => { + endian = Some(match value { + "little" => Endian::Little, + "big" => Endian::Big, + s => panic!("unexpected {s}"), + }) + } + _ => {} + } + } + } + TargetCfg { + arch: arch.unwrap().to_string(), + os: os.unwrap().to_string(), + env: env.unwrap().to_string(), + abi: abi.unwrap().to_string(), + families, + pointer_width: pointer_width.unwrap(), + endian: endian.unwrap(), + } + } } #[derive(Debug, Clone)] diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index f8f193ddf83..8f097f47b45 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -661,17 +661,36 @@ impl Config { let name = line[prefix.len() + 1..].split(&[':', ' '][..]).next().unwrap(); + let matches_pointer_width = || { + name.strip_suffix("bit") + .and_then(|width| width.parse::<u32>().ok()) + .map(|width| self.get_pointer_width() == width) + .unwrap_or(false) + }; + + // If something is ignored for emscripten, it likely also needs to be + // ignored for wasm32-unknown-unknown. + // `wasm32-bare` is an alias to refer to just wasm32-unknown-unknown + // (in contrast to `wasm32` which also matches non-bare targets like + // asmjs-unknown-emscripten). + let matches_wasm32_alias = || { + self.target == "wasm32-unknown-unknown" && matches!(name, "emscripten" | "wasm32-bare") + }; + let is_match = name == "test" || self.target == name || // triple - util::matches_os(&self.target, name) || // target - util::matches_env(&self.target, name) || // env + self.matches_os(name) || + self.matches_env(name) || + self.matches_abi(name) || + self.matches_family(name) || self.target.ends_with(name) || // target and env - name == util::get_arch(&self.target) || // architecture - name == util::get_pointer_width(&self.target) || // pointer width + self.matches_arch(name) || + matches_wasm32_alias() || + matches_pointer_width() || name == self.stage_id.split('-').next().unwrap() || // stage name == self.channel || // channel (self.target != self.host && name == "cross-compile") || - (name == "endian-big" && util::is_big_endian(&self.target)) || + (name == "endian-big" && self.is_big_endian()) || (self.remote_test_client.is_some() && name == "remote") || match self.compare_mode { Some(CompareMode::Polonius) => name == "compare-mode-polonius", @@ -869,7 +888,7 @@ pub fn make_test_description<R: Read>( let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some(); let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(); - let has_asm_support = util::has_asm_support(&config.target); + let has_asm_support = config.has_asm_support(); let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target); let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target); let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target); diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index a8fd4880f07..bcd222b5a93 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -42,7 +42,6 @@ fn config() -> Config { "--suite=ui", "--compile-lib-path=", "--run-lib-path=", - "--rustc-path=", "--python=", "--jsondocck-path=", "--src-base=", @@ -57,7 +56,24 @@ fn config() -> Config { "--target=x86_64-unknown-linux-gnu", "--channel=nightly", ]; - let args = args.iter().map(ToString::to_string).collect(); + let mut args: Vec<String> = args.iter().map(ToString::to_string).collect(); + args.push("--rustc-path".to_string()); + // This is a subtle/fragile thing. On rust-lang CI, there is no global + // `rustc`, and Cargo doesn't offer a convenient way to get the path to + // `rustc`. Fortunately bootstrap sets `RUSTC` for us, which is pointing + // to the stage0 compiler. + // + // Otherwise, if you are running compiletests's tests manually, you + // probably don't have `RUSTC` set, in which case this falls back to the + // global rustc. If your global rustc is too far out of sync with stage0, + // then this may cause confusing errors. Or if for some reason you don't + // have rustc in PATH, that would also fail. + args.push(std::env::var("RUSTC").unwrap_or_else(|_| { + eprintln!( + "warning: RUSTC not set, using global rustc (are you not running via bootstrap?)" + ); + "rustc".to_string() + })); crate::parse_config(args) } @@ -237,13 +253,20 @@ fn sanitizers() { #[test] fn asm_support() { - let mut config = config(); - - config.target = "avr-unknown-gnu-atmega328".to_owned(); - assert!(check_ignore(&config, "// needs-asm-support")); - - config.target = "i686-unknown-netbsd".to_owned(); - assert!(!check_ignore(&config, "// needs-asm-support")); + let asms = [ + ("avr-unknown-gnu-atmega328", false), + ("i686-unknown-netbsd", true), + ("riscv32gc-unknown-linux-gnu", true), + ("riscv64imac-unknown-none-elf", true), + ("x86_64-unknown-linux-gnu", true), + ("i686-unknown-netbsd", true), + ]; + for (target, has_asm) in asms { + let mut config = config(); + config.target = target.to_string(); + assert_eq!(config.has_asm_support(), has_asm); + assert_eq!(check_ignore(&config, "// needs-asm-support"), !has_asm) + } } #[test] @@ -281,3 +304,155 @@ fn test_duplicate_revisions() { let config = config(); parse_rs(&config, "// revisions: rpass1 rpass1"); } + +#[test] +fn ignore_arch() { + let archs = [ + ("x86_64-unknown-linux-gnu", "x86_64"), + ("i686-unknown-linux-gnu", "x86"), + ("nvptx64-nvidia-cuda", "nvptx64"), + ("asmjs-unknown-emscripten", "wasm32"), + ("asmjs-unknown-emscripten", "asmjs"), + ("thumbv7m-none-eabi", "thumb"), + ]; + for (target, arch) in archs { + let mut config = config(); + config.target = target.to_string(); + assert!(config.matches_arch(arch), "{target} {arch}"); + assert!(check_ignore(&config, &format!("// ignore-{arch}"))); + } +} + +#[test] +fn matches_os() { + let oss = [ + ("x86_64-unknown-linux-gnu", "linux"), + ("x86_64-fortanix-unknown-sgx", "unknown"), + ("wasm32-unknown-unknown", "unknown"), + ("x86_64-unknown-none", "none"), + ]; + for (target, os) in oss { + let mut config = config(); + config.target = target.to_string(); + assert!(config.matches_os(os), "{target} {os}"); + assert!(check_ignore(&config, &format!("// ignore-{os}"))); + } +} + +#[test] +fn matches_env() { + let envs = [ + ("x86_64-unknown-linux-gnu", "gnu"), + ("x86_64-fortanix-unknown-sgx", "sgx"), + ("arm-unknown-linux-musleabi", "musl"), + ]; + for (target, env) in envs { + let mut config = config(); + config.target = target.to_string(); + assert!(config.matches_env(env), "{target} {env}"); + assert!(check_ignore(&config, &format!("// ignore-{env}"))); + } +} + +#[test] +fn matches_abi() { + let abis = [ + ("aarch64-apple-ios-macabi", "macabi"), + ("x86_64-unknown-linux-gnux32", "x32"), + ("arm-unknown-linux-gnueabi", "eabi"), + ]; + for (target, abi) in abis { + let mut config = config(); + config.target = target.to_string(); + assert!(config.matches_abi(abi), "{target} {abi}"); + assert!(check_ignore(&config, &format!("// ignore-{abi}"))); + } +} + +#[test] +fn is_big_endian() { + let endians = [ + ("x86_64-unknown-linux-gnu", false), + ("bpfeb-unknown-none", true), + ("m68k-unknown-linux-gnu", true), + ("aarch64_be-unknown-linux-gnu", true), + ("powerpc64-unknown-linux-gnu", true), + ]; + for (target, is_big) in endians { + let mut config = config(); + config.target = target.to_string(); + assert_eq!(config.is_big_endian(), is_big, "{target} {is_big}"); + assert_eq!(check_ignore(&config, "// ignore-endian-big"), is_big); + } +} + +#[test] +fn pointer_width() { + let widths = [ + ("x86_64-unknown-linux-gnu", 64), + ("i686-unknown-linux-gnu", 32), + ("arm64_32-apple-watchos", 32), + ("msp430-none-elf", 16), + ]; + for (target, width) in widths { + let mut config = config(); + config.target = target.to_string(); + assert_eq!(config.get_pointer_width(), width, "{target} {width}"); + assert_eq!(check_ignore(&config, "// ignore-16bit"), width == 16); + assert_eq!(check_ignore(&config, "// ignore-32bit"), width == 32); + assert_eq!(check_ignore(&config, "// ignore-64bit"), width == 64); + } +} + +#[test] +fn wasm_special() { + let ignores = [ + ("wasm32-unknown-unknown", "emscripten", true), + ("wasm32-unknown-unknown", "wasm32", true), + ("wasm32-unknown-unknown", "wasm32-bare", true), + ("wasm32-unknown-unknown", "wasm64", false), + ("asmjs-unknown-emscripten", "emscripten", true), + ("asmjs-unknown-emscripten", "wasm32", true), + ("asmjs-unknown-emscripten", "wasm32-bare", false), + ("wasm32-unknown-emscripten", "emscripten", true), + ("wasm32-unknown-emscripten", "wasm32", true), + ("wasm32-unknown-emscripten", "wasm32-bare", false), + ("wasm32-wasi", "emscripten", false), + ("wasm32-wasi", "wasm32", true), + ("wasm32-wasi", "wasm32-bare", false), + ("wasm32-wasi", "wasi", true), + ("wasm64-unknown-unknown", "emscripten", false), + ("wasm64-unknown-unknown", "wasm32", false), + ("wasm64-unknown-unknown", "wasm32-bare", false), + ("wasm64-unknown-unknown", "wasm64", true), + ]; + for (target, pattern, ignore) in ignores { + let mut config = config(); + config.target = target.to_string(); + assert_eq!( + check_ignore(&config, &format!("// ignore-{pattern}")), + ignore, + "{target} {pattern}" + ); + } +} + +#[test] +fn families() { + let families = [ + ("x86_64-unknown-linux-gnu", "unix"), + ("x86_64-pc-windows-gnu", "windows"), + ("wasm32-unknown-unknown", "wasm"), + ("wasm32-unknown-emscripten", "wasm"), + ("wasm32-unknown-emscripten", "unix"), + ]; + for (target, family) in families { + let mut config = config(); + config.target = target.to_string(); + assert!(config.matches_family(family)); + let other = if family == "windows" { "unix" } else { "windows" }; + assert!(!config.matches_family(other)); + assert!(check_ignore(&config, &format!("// ignore-{family}"))); + assert!(!check_ignore(&config, &format!("// ignore-{other}"))); + } +} diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index a8a151ca114..ac6d80bb439 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -11,6 +11,7 @@ use crate::common::{ use crate::common::{CompareMode, Config, Debugger, Mode, PassMode, TestPaths}; use crate::util::logv; use getopts::Options; +use lazycell::LazyCell; use std::env; use std::ffi::OsString; use std::fs; @@ -299,6 +300,8 @@ pub fn parse_config(args: Vec<String>) -> Config { npm: matches.opt_str("npm"), force_rerun: matches.opt_present("force-rerun"), + + target_cfg: LazyCell::new(), } } @@ -441,7 +444,7 @@ fn configure_cdb(config: &Config) -> Option<Config> { fn configure_gdb(config: &Config) -> Option<Config> { config.gdb_version?; - if util::matches_env(&config.target, "msvc") { + if config.matches_env("msvc") { return None; } diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index d3e5a2dd644..47f2a2d3482 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -13,7 +13,6 @@ use crate::errors::{self, Error, ErrorKind}; use crate::header::TestProps; use crate::json; use crate::read2::read2_abbreviated; -use crate::util::get_pointer_width; use crate::util::{logv, PathBufExt}; use crate::ColorConfig; use regex::{Captures, Regex}; @@ -3127,7 +3126,7 @@ impl<'test> TestCx<'test> { output_kind: TestOutput, explicit_format: bool, ) -> usize { - let stderr_bits = format!("{}.stderr", get_pointer_width(&self.config.target)); + let stderr_bits = format!("{}bit.stderr", self.config.get_pointer_width()); let (stderr_kind, stdout_kind) = match output_kind { TestOutput::Compile => ( { @@ -3402,7 +3401,7 @@ impl<'test> TestCx<'test> { let mut bit_width = String::new(); if test_file_contents.lines().any(|l| l == "// EMIT_MIR_FOR_EACH_BIT_WIDTH") { - bit_width = format!(".{}", get_pointer_width(&self.config.target)); + bit_width = format!(".{}bit", self.config.get_pointer_width()); } if self.config.bless { diff --git a/src/tools/compiletest/src/util.rs b/src/tools/compiletest/src/util.rs index 22df18ee9fb..9d047b63c85 100644 --- a/src/tools/compiletest/src/util.rs +++ b/src/tools/compiletest/src/util.rs @@ -8,84 +8,6 @@ use tracing::*; #[cfg(test)] mod tests; -/// Conversion table from triple OS name to Rust SYSNAME -const OS_TABLE: &[(&str, &str)] = &[ - ("android", "android"), - ("androideabi", "android"), - ("cuda", "cuda"), - ("darwin", "macos"), - ("dragonfly", "dragonfly"), - ("emscripten", "emscripten"), - ("freebsd", "freebsd"), - ("fuchsia", "fuchsia"), - ("haiku", "haiku"), - ("hermit", "hermit"), - ("illumos", "illumos"), - ("ios", "ios"), - ("l4re", "l4re"), - ("linux", "linux"), - ("mingw32", "windows"), - ("none", "none"), - ("netbsd", "netbsd"), - ("openbsd", "openbsd"), - ("redox", "redox"), - ("sgx", "sgx"), - ("solaris", "solaris"), - ("watchos", "watchos"), - ("win32", "windows"), - ("windows", "windows"), - ("vxworks", "vxworks"), -]; - -const ARCH_TABLE: &[(&str, &str)] = &[ - ("aarch64", "aarch64"), - ("aarch64_be", "aarch64"), - ("amd64", "x86_64"), - ("arm", "arm"), - ("arm64", "aarch64"), - ("armv4t", "arm"), - ("armv5te", "arm"), - ("armv7", "arm"), - ("armv7s", "arm"), - ("asmjs", "asmjs"), - ("avr", "avr"), - ("bpfeb", "bpf"), - ("bpfel", "bpf"), - ("hexagon", "hexagon"), - ("i386", "x86"), - ("i586", "x86"), - ("i686", "x86"), - ("m68k", "m68k"), - ("mips", "mips"), - ("mips64", "mips64"), - ("mips64el", "mips64"), - ("mipsisa32r6", "mips"), - ("mipsisa32r6el", "mips"), - ("mipsisa64r6", "mips64"), - ("mipsisa64r6el", "mips64"), - ("mipsel", "mips"), - ("mipsisa32r6", "mips"), - ("mipsisa32r6el", "mips"), - ("mipsisa64r6", "mips64"), - ("mipsisa64r6el", "mips64"), - ("msp430", "msp430"), - ("nvptx64", "nvptx64"), - ("powerpc", "powerpc"), - ("powerpc64", "powerpc64"), - ("powerpc64le", "powerpc64"), - ("riscv64gc", "riscv64"), - ("s390x", "s390x"), - ("sparc", "sparc"), - ("sparc64", "sparc64"), - ("sparcv9", "sparc64"), - ("thumbv6m", "thumb"), - ("thumbv7em", "thumb"), - ("thumbv7m", "thumb"), - ("wasm32", "wasm32"), - ("x86_64", "x86_64"), - ("xcore", "xcore"), -]; - pub const ASAN_SUPPORTED_TARGETS: &[&str] = &[ "aarch64-apple-darwin", "aarch64-fuchsia", @@ -140,80 +62,6 @@ pub const MEMTAG_SUPPORTED_TARGETS: &[&str] = pub const SHADOWCALLSTACK_SUPPORTED_TARGETS: &[&str] = &["aarch64-linux-android"]; -const BIG_ENDIAN: &[&str] = &[ - "aarch64_be", - "armebv7r", - "mips", - "mips64", - "mipsisa32r6", - "mipsisa64r6", - "powerpc", - "powerpc64", - "s390x", - "sparc", - "sparc64", - "sparcv9", -]; - -static ASM_SUPPORTED_ARCHS: &[&str] = &[ - "x86", "x86_64", "arm", "aarch64", "riscv32", - "riscv64", - // These targets require an additional asm_experimental_arch feature. - // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32", -]; - -pub fn has_asm_support(triple: &str) -> bool { - ASM_SUPPORTED_ARCHS.contains(&get_arch(triple)) -} - -pub fn matches_os(triple: &str, name: &str) -> bool { - // For the wasm32 bare target we ignore anything also ignored on emscripten - // and then we also recognize `wasm32-bare` as the os for the target - if triple == "wasm32-unknown-unknown" { - return name == "emscripten" || name == "wasm32-bare"; - } - let triple: Vec<_> = triple.split('-').collect(); - for &(triple_os, os) in OS_TABLE { - if triple.contains(&triple_os) { - return os == name; - } - } - panic!("Cannot determine OS from triple"); -} - -/// Determine the architecture from `triple` -pub fn get_arch(triple: &str) -> &'static str { - let triple: Vec<_> = triple.split('-').collect(); - for &(triple_arch, arch) in ARCH_TABLE { - if triple.contains(&triple_arch) { - return arch; - } - } - panic!("Cannot determine Architecture from triple"); -} - -/// Determine the endianness from `triple` -pub fn is_big_endian(triple: &str) -> bool { - let triple_arch = triple.split('-').next().unwrap(); - BIG_ENDIAN.contains(&triple_arch) -} - -pub fn matches_env(triple: &str, name: &str) -> bool { - if let Some(env) = triple.split('-').nth(3) { env.starts_with(name) } else { false } -} - -pub fn get_pointer_width(triple: &str) -> &'static str { - if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32")) - || triple.starts_with("s390x") - { - "64bit" - } else if triple.starts_with("avr") { - "16bit" - } else { - "32bit" - } -} - pub fn make_new_path(path: &str) -> String { assert!(cfg!(windows)); // Windows just uses PATH as the library search path, so we have to diff --git a/src/tools/compiletest/src/util/tests.rs b/src/tools/compiletest/src/util/tests.rs index 663027173ff..b09a183b14e 100644 --- a/src/tools/compiletest/src/util/tests.rs +++ b/src/tools/compiletest/src/util/tests.rs @@ -1,43 +1,6 @@ use super::*; #[test] -#[should_panic(expected = "Cannot determine Architecture from triple")] -fn test_get_arch_failure() { - get_arch("abc"); -} - -#[test] -fn test_get_arch() { - assert_eq!("x86_64", get_arch("x86_64-unknown-linux-gnu")); - assert_eq!("x86_64", get_arch("amd64")); - assert_eq!("nvptx64", get_arch("nvptx64-nvidia-cuda")); -} - -#[test] -#[should_panic(expected = "Cannot determine OS from triple")] -fn test_matches_os_failure() { - matches_os("abc", "abc"); -} - -#[test] -fn test_matches_os() { - assert!(matches_os("x86_64-unknown-linux-gnu", "linux")); - assert!(matches_os("wasm32-unknown-unknown", "emscripten")); - assert!(matches_os("wasm32-unknown-unknown", "wasm32-bare")); - assert!(!matches_os("wasm32-unknown-unknown", "windows")); - assert!(matches_os("thumbv6m0-none-eabi", "none")); - assert!(matches_os("riscv32imc-unknown-none-elf", "none")); - assert!(matches_os("nvptx64-nvidia-cuda", "cuda")); - assert!(matches_os("x86_64-fortanix-unknown-sgx", "sgx")); -} - -#[test] -fn is_big_endian_test() { - assert!(!is_big_endian("no")); - assert!(is_big_endian("sparc-unknown-unknown")); -} - -#[test] fn path_buf_with_extra_extension_test() { assert_eq!( PathBuf::from("foo.rs.stderr"), diff --git a/src/tools/miri b/src/tools/miri -Subproject b938529fb8ed8f7b5b374282ffc3ffa74c31311 +Subproject 39ee5747153bf13324870c4a912acbf1f9bfde3 diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js index a5121850369..70d5f94472f 100644 --- a/src/tools/rustdoc-gui/tester.js +++ b/src/tools/rustdoc-gui/tester.js @@ -201,6 +201,19 @@ async function main(argv) { process.setMaxListeners(opts["jobs"] + 1); } + // We catch this "event" to display a nicer message in case of unexpected exit (because of a + // missing `--no-sandbox`). + const exitHandling = (code) => { + if (!opts["no_sandbox"]) { + console.log(""); + console.log( + "`browser-ui-test` crashed unexpectedly. Please try again with adding `--test-args \ +--no-sandbox` at the end. For example: `x.py test src/test/rustdoc-gui --test-args --no-sandbox`"); + console.log(""); + } + }; + process.on('exit', exitHandling); + const tests_queue = []; let results = { successful: [], @@ -247,6 +260,9 @@ async function main(argv) { } status_bar.finish(); + // We don't need this listener anymore. + process.removeListener("exit", exitHandling); + if (debug) { results.successful.sort(by_filename); results.successful.forEach(r => { diff --git a/src/tools/rustfmt/src/chains.rs b/src/tools/rustfmt/src/chains.rs index e26e24ec55a..fcc02eca429 100644 --- a/src/tools/rustfmt/src/chains.rs +++ b/src/tools/rustfmt/src/chains.rs @@ -145,7 +145,7 @@ impl ChainItemKind { fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, Span) { let (kind, span) = match expr.kind { - ast::ExprKind::MethodCall(ref segment, ref expressions, _) => { + ast::ExprKind::MethodCall(ref segment, ref receiver, ref expressions, _) => { let types = if let Some(ref generic_args) = segment.args { if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args { data.args @@ -163,7 +163,7 @@ impl ChainItemKind { } else { vec![] }; - let span = mk_sp(expressions[0].span.hi(), expr.span.hi()); + let span = mk_sp(receiver.span.hi(), expr.span.hi()); let kind = ChainItemKind::MethodCall(segment.clone(), types, expressions.clone()); (kind, span) } @@ -253,7 +253,7 @@ impl ChainItem { format!("::<{}>", type_list.join(", ")) }; let callee_str = format!(".{}{}", rewrite_ident(context, method_name), type_str); - rewrite_call(context, &callee_str, &args[1..], span, shape) + rewrite_call(context, &callee_str, &args, span, shape) } } @@ -400,8 +400,8 @@ impl Chain { // is a try! macro, we'll convert it to shorthand when the option is set. fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext<'_>) -> Option<ast::Expr> { match expr.kind { - ast::ExprKind::MethodCall(_, ref expressions, _) => { - Some(Self::convert_try(&expressions[0], context)) + ast::ExprKind::MethodCall(_, ref receiver, _, _) => { + Some(Self::convert_try(&receiver, context)) } ast::ExprKind::Field(ref subexpr, _) | ast::ExprKind::Try(ref subexpr) diff --git a/src/tools/tidy/src/bins.rs b/src/tools/tidy/src/bins.rs index 9615c4db6b4..025b8ab9f0a 100644 --- a/src/tools/tidy/src/bins.rs +++ b/src/tools/tidy/src/bins.rs @@ -96,6 +96,8 @@ mod os_impl { #[cfg(unix)] pub fn check(path: &Path, bad: &mut bool) { + use std::ffi::OsStr; + const ALLOWED: &[&str] = &["configure"]; crate::walk_no_read( @@ -117,9 +119,9 @@ mod os_impl { }, &mut |entry| { let file = entry.path(); - let filename = file.file_name().unwrap().to_string_lossy(); - let extensions = [".py", ".sh"]; - if extensions.iter().any(|e| filename.ends_with(e)) { + let extension = file.extension(); + let scripts = ["py", "sh", "ps1"]; + if scripts.into_iter().any(|e| extension == Some(OsStr::new(e))) { return; } diff --git a/x.ps1 b/x.ps1 new file mode 100755 index 00000000000..1225443735f --- /dev/null +++ b/x.ps1 @@ -0,0 +1,28 @@ +#!/usr/bin/env pwsh + +# See x.sh for why these scripts exist. + +$xpy = Join-Path $PSScriptRoot x.py +# Start-Process for some reason splits arguments on spaces. (Isn't powershell supposed to be simpler than bash?) +# Double-quote all the arguments so it doesn't do that. +$xpy_args = @("""$xpy""") +foreach ($arg in $args) { + $xpy_args += """$arg""" +} + +foreach ($python in "py", "python3", "python", "python2") { + # NOTE: this only tests that the command exists in PATH, not that it's actually + # executable. The latter is not possible in a portable way, see + # https://github.com/PowerShell/PowerShell/issues/12625. + if (Get-Command $python -ErrorAction SilentlyContinue) { + if ($python -eq "py") { + # Use python3, not python2 + $xpy_args = @("-3") + $xpy_args + } + $process = Start-Process -NoNewWindow -Wait -PassThru $python $xpy_args + Exit $process.ExitCode + } +} + +Write-Error "${PSCommandPath}: error: did not find python installed" +Exit 1 diff --git a/x.py b/x.py index 0289056fdcb..6c68907c581 100755 --- a/x.py +++ b/x.py @@ -1,36 +1,16 @@ -#!/usr/bin/env bash +#!/usr/bin/env python3 +# Some systems don't have `python3` in their PATH. This isn't supported by x.py directly; +# they should use `x.sh` or `x.ps1` instead. -# Modern Linux and macOS systems commonly only have a thing called `python3` and -# not `python`, while Windows commonly does not have `python3`, so we cannot -# directly use python in the shebang and have it consistently work. Instead we -# embed some bash to look for a python to run the rest of the script. -# -# On Windows, `py -3` sometimes works. We need to try it first because `python3` -# sometimes tries to launch the app store on Windows. -'''': -for PYTHON in "py -3" python3 python python2; do - if command -v $PYTHON >/dev/null; then - exec $PYTHON "$0" "$@" - break - fi -done -echo "$0: error: did not find python installed" >&2 -exit 1 -''' - -# The rest of this file is Python. -# # This file is only a "symlink" to bootstrap.py, all logic should go there. import os import sys # If this is python2, check if python3 is available and re-execute with that -# interpreter. +# interpreter. Only python3 allows downloading CI LLVM. # -# `./x.py` would not normally benefit from this because the bash above tries -# python3 before 2, but this matters if someone ran `python x.py` and their -# system's `python` is python2. +# This matters if someone's system `python` is python2. if sys.version_info.major < 3: try: os.execvp("py", ["py", "-3"] + sys.argv) diff --git a/x.sh b/x.sh new file mode 100755 index 00000000000..704d0f791f3 --- /dev/null +++ b/x.sh @@ -0,0 +1,33 @@ +#!/bin/sh + +# Modern Linux and macOS systems commonly only have a thing called `python3` and +# not `python`, while Windows commonly does not have `python3`, so we cannot +# directly use python in the x.py shebang and have it consistently work. Instead we +# have a shell script to look for a python to run x.py. + +set -eu + +realpath() { + if [ -d "$1" ]; then + CDPATH='' command cd "$1" && pwd -P + else + echo "$(realpath "$(dirname "$1")")/$(basename "$1")" + fi +} + +xpy=$(dirname "$(realpath "$0")")/x.py + +# On Windows, `py -3` sometimes works. We need to try it first because `python3` +# sometimes tries to launch the app store on Windows. +for SEARCH_PYTHON in py python3 python python2; do + if python=$(command -v $SEARCH_PYTHON) && [ -x "$python" ]; then + if [ $SEARCH_PYTHON = py ]; then + extra_arg="-3" + else + extra_arg="" + fi + exec "$python" $extra_arg "$xpy" "$@" + fi +done +echo "$0: error: did not find python installed" >&2 +exit 1 |
