diff options
1295 files changed, 19345 insertions, 11011 deletions
diff --git a/.mailmap b/.mailmap index cd617ca2f42..213aa6eff66 100644 --- a/.mailmap +++ b/.mailmap @@ -43,6 +43,7 @@ Brian Anderson <banderson@mozilla.com> <andersrb@gmail.com> Brian Anderson <banderson@mozilla.com> <banderson@mozilla.org> Brian Dawn <brian.t.dawn@gmail.com> Brian Leibig <brian@brianleibig.com> Brian Leibig <brian.leibig@gmail.com> +Noah Lev <camelidcamel@gmail.com> Noah Lev <camelidcamel@gmail.com> <37223377+camelid@users.noreply.github.com> Carl-Anton Ingmarsson <mail@carlanton.se> <ca.ingmarsson@gmail.com> Carol (Nichols || Goulding) <carol.nichols@gmail.com> <193874+carols10cents@users.noreply.github.com> diff --git a/Cargo.lock b/Cargo.lock index da65b376d19..5c1736c692e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -278,6 +278,7 @@ dependencies = [ "humantime 2.0.1", "ignore", "im-rc", + "itertools 0.10.0", "jobserver", "lazy_static", "lazycell", @@ -293,7 +294,7 @@ dependencies = [ "rand 0.8.3", "rustc-workspace-hack", "rustfix", - "semver 0.10.0", + "semver 1.0.1", "serde", "serde_ignored", "serde_json", @@ -441,9 +442,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" +checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" dependencies = [ "jobserver", ] @@ -551,10 +552,10 @@ name = "clippy" version = "0.1.54" dependencies = [ "cargo_metadata 0.12.0", - "clippy-mini-macro-test", "clippy_lints", "compiletest_rs", "derive-new", + "filetime", "quote", "regex", "rustc-workspace-hack", @@ -567,10 +568,6 @@ dependencies = [ ] [[package]] -name = "clippy-mini-macro-test" -version = "0.2.0" - -[[package]] name = "clippy_dev" version = "0.0.1" dependencies = [ @@ -655,9 +652,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65af2dcae4779003dfa91aedc6ade7bdc7ba685944e50a8b4f9380df376a4466" +checksum = "787187ae221adfcda34b03006f1617099e4ae26b50e5a4db282496014ab75837" dependencies = [ "cc", "rustc-std-workspace-core", @@ -1716,6 +1713,15 @@ dependencies = [ ] [[package]] +name = "itertools" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319" +dependencies = [ + "either", +] + +[[package]] name = "itoa" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1743,11 +1749,10 @@ dependencies = [ "fs-err", "getopts", "jsonpath_lib", - "lazy_static", + "once_cell", "regex", - "serde", "serde_json", - "shlex 0.1.1", + "shlex", ] [[package]] @@ -2128,16 +2133,16 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "shlex 1.0.0", + "shlex", "tempfile", "toml", ] [[package]] name = "measureme" -version = "9.1.1" +version = "9.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49cf14eb7d2eea897d9949b68f19e165638755e3a1a3c0941b6b6c3e00141f2c" +checksum = "78f7a41bc6f856a2cf0e95094ad5121f82500e2d9a0f3c0171d98f6566d8117d" dependencies = [ "log", "memmap2", @@ -2195,9 +2200,9 @@ dependencies = [ [[package]] name = "minifier" -version = "0.0.39" +version = "0.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6cdf618de5c9c98d4a7b2e0d1f1e44f82a19196cfd94040bb203621c25d28d98" +checksum = "5594542d20834f2b974f5e5fb8e0cf1c67a2119dcadc29ef5d93a081fb30cc08" dependencies = [ "macro-utils", ] @@ -2289,6 +2294,7 @@ dependencies = [ "hex 0.4.2", "libc", "log", + "measureme", "rand 0.8.3", "rustc-workspace-hack", "rustc_version", @@ -2845,9 +2851,9 @@ dependencies = [ [[package]] name = "racer" -version = "2.1.46" +version = "2.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7cbda48a9124ed2e83766d2c15e3725710d344abca35fad8cf52341a55883b1" +checksum = "513c70e67444a0d62fdc581dffa521c6820942a5f08300d0864863f8d0e750e3" dependencies = [ "bitflags", "clap", @@ -3876,6 +3882,7 @@ dependencies = [ "rand 0.7.3", "rustc_ast", "rustc_data_structures", + "rustc_errors", "rustc_fs_util", "rustc_graphviz", "rustc_hir", @@ -4673,6 +4680,15 @@ dependencies = [ ] [[package]] +name = "semver" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d023dabf011d5dcb5ac64e3685d97d3b0ef412911077a2851455c6098524a723" +dependencies = [ + "serde", +] + +[[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4794,12 +4810,6 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] name = "shlex" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" - -[[package]] -name = "shlex" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42a568c8f2cd051a4d283bd6eb0343ac214c1b0f1ac19f93e1175b2dee38c73d" @@ -5031,9 +5041,9 @@ dependencies = [ [[package]] name = "tar" -version = "0.4.33" +version = "0.4.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0bcfbd6a598361fda270d82469fff3d65089dc33e175c9a131f7b4cd395f228" +checksum = "7d779dc6aeff029314570f666ec83f19df7280bb36ef338442cfa8c604021b80" dependencies = [ "filetime", "libc", diff --git a/README.md b/README.md index 5ec94e189f8..af6a4090a27 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,28 @@ Read ["Installation"] from [The Book]. ## Installing from Source The Rust build system uses a Python script called `x.py` to build the compiler, -which manages the bootstrapping process. More information about it can be found -by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. +which manages the bootstrapping process. It lives in the root of the project. + +The `x.py` command can be run directly on most systems in the following format: + +```sh +./x.py <subcommand> [flags] +``` + +This is how the documentation and examples assume you are running `x.py`. + +Systems such as Ubuntu 20.04 LTS do not create the necessary `python` command by default when Python is installed that allows `x.py` to be run directly. In that case you can either create a symlink for `python` (Ubuntu provides the `python-is-python3` package for this), or run `x.py` using Python itself: + +```sh +# Python 3 +python3 x.py <subcommand> [flags] + +# Python 2.7 +python2.7 x.py <subcommand> [flags] +``` + +More information about `x.py` can be found +by running it with the `--help` flag or reading the [rustc dev guide][rustcguidebuild]. [gettingstarted]: https://rustc-dev-guide.rust-lang.org/getting-started.html [rustcguidebuild]: https://rustc-dev-guide.rust-lang.org/building/how-to-build-and-run.html diff --git a/RELEASES.md b/RELEASES.md index 92312d8d556..60b3359c1b6 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,24 @@ +Version 1.52.1 (2021-05-10) +============================ + +This release disables incremental compilation, unless the user has explicitly +opted in via the newly added RUSTC_FORCE_INCREMENTAL=1 environment variable. + +This is due to the widespread, and frequently occuring, breakage encountered by +Rust users due to newly enabled incremental verification in 1.52.0. Notably, +Rust users **should** upgrade to 1.52.0 or 1.52.1: the bugs that are detected by +newly added incremental verification are still present in past stable versions, +and are not yet fixed on any channel. These bugs can lead to miscompilation of +Rust binaries. + +These problems only affect incremental builds, so release builds with Cargo +should not be affected unless the user has explicitly opted into incremental. +Debug and check builds are affected. + +See [84970] for more details. + +[84970]: https://github.com/rust-lang/rust/issues/84970 + Version 1.52.0 (2021-05-06) ============================ diff --git a/compiler/rustc_apfloat/src/lib.rs b/compiler/rustc_apfloat/src/lib.rs index c648147d108..7eeec4aa86b 100644 --- a/compiler/rustc_apfloat/src/lib.rs +++ b/compiler/rustc_apfloat/src/lib.rs @@ -35,7 +35,6 @@ #![forbid(unsafe_code)] #![feature(iter_zip)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #[macro_use] extern crate alloc; diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index ffec28a395f..7c79b4aab3c 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -10,15 +10,13 @@ )] #![feature(box_syntax)] #![feature(box_patterns)] -#![cfg_attr(bootstrap, feature(const_fn))] // For the `transmute` in `P::new` -#![cfg_attr(not(bootstrap), feature(const_fn_unsize))] // For the `transmute` in `P::new` +#![cfg_attr(bootstrap, feature(const_fn_unsize))] #![feature(const_fn_transmute)] -#![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(iter_zip)] #![feature(label_break_value)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] +#![feature(min_specialization)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 483135ed3a3..866f2180bb6 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -560,8 +560,8 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } - /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_ok(<expr>) }`, - /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_ok(()) }` + /// Desugar `try { <stmts>; <expr> }` into `{ <stmts>; ::std::ops::Try::from_output(<expr>) }`, + /// `try { <stmts>; }` into `{ <stmts>; ::std::ops::Try::from_output(()) }` /// and save the block id to use it as a break target for desugaring of the `?` operator. fn lower_expr_try_block(&mut self, body: &Block) -> hir::ExprKind<'hir> { self.with_catch_scope(body.id, |this| { @@ -590,9 +590,9 @@ impl<'hir> LoweringContext<'_, 'hir> { let ok_wrapped_span = this.mark_span_with_reason(DesugaringKind::TryBlock, tail_expr.span, None); - // `::std::ops::Try::from_ok($tail_expr)` + // `::std::ops::Try::from_output($tail_expr)` block.expr = Some(this.wrap_in_try_constructor( - hir::LangItem::TryFromOk, + hir::LangItem::TryTraitFromOutput, try_span, tail_expr, ok_wrapped_span, @@ -1579,14 +1579,14 @@ impl<'hir> LoweringContext<'_, 'hir> { self.allow_try_trait.clone(), ); - // `Try::into_result(<expr>)` + // `Try::branch(<expr>)` let scrutinee = { // expand <expr> let sub_expr = self.lower_expr_mut(sub_expr); self.expr_call_lang_item_fn( unstable_span, - hir::LangItem::TryIntoResult, + hir::LangItem::TryTraitBranch, arena_vec![self; sub_expr], ) }; @@ -1604,8 +1604,8 @@ impl<'hir> LoweringContext<'_, 'hir> { }; let attrs = vec![attr]; - // `Ok(val) => #[allow(unreachable_code)] val,` - let ok_arm = { + // `ControlFlow::Continue(val) => #[allow(unreachable_code)] val,` + let continue_arm = { let val_ident = Ident::with_dummy_span(sym::val); let (val_pat, val_pat_nid) = self.pat_ident(span, val_ident); let val_expr = self.arena.alloc(self.expr_ident_with_attrs( @@ -1614,27 +1614,21 @@ impl<'hir> LoweringContext<'_, 'hir> { val_pat_nid, ThinVec::from(attrs.clone()), )); - let ok_pat = self.pat_ok(span, val_pat); - self.arm(ok_pat, val_expr) + let continue_pat = self.pat_cf_continue(unstable_span, val_pat); + self.arm(continue_pat, val_expr) }; - // `Err(err) => #[allow(unreachable_code)] - // return Try::from_error(From::from(err)),` - let err_arm = { - let err_ident = Ident::with_dummy_span(sym::err); - let (err_local, err_local_nid) = self.pat_ident(try_span, err_ident); - let from_expr = { - let err_expr = self.expr_ident_mut(try_span, err_ident, err_local_nid); - self.expr_call_lang_item_fn( - try_span, - hir::LangItem::FromFrom, - arena_vec![self; err_expr], - ) - }; - let from_err_expr = self.wrap_in_try_constructor( - hir::LangItem::TryFromError, - unstable_span, - from_expr, + // `ControlFlow::Break(residual) => + // #[allow(unreachable_code)] + // return Try::from_residual(residual),` + let break_arm = { + let residual_ident = Ident::with_dummy_span(sym::residual); + let (residual_local, residual_local_nid) = self.pat_ident(try_span, residual_ident); + let residual_expr = self.expr_ident_mut(try_span, residual_ident, residual_local_nid); + let from_residual_expr = self.wrap_in_try_constructor( + hir::LangItem::TryTraitFromResidual, + try_span, + self.arena.alloc(residual_expr), unstable_span, ); let thin_attrs = ThinVec::from(attrs); @@ -1645,25 +1639,25 @@ impl<'hir> LoweringContext<'_, 'hir> { try_span, hir::ExprKind::Break( hir::Destination { label: None, target_id }, - Some(from_err_expr), + Some(from_residual_expr), ), thin_attrs, )) } else { self.arena.alloc(self.expr( try_span, - hir::ExprKind::Ret(Some(from_err_expr)), + hir::ExprKind::Ret(Some(from_residual_expr)), thin_attrs, )) }; - let err_pat = self.pat_err(try_span, err_local); - self.arm(err_pat, ret_expr) + let break_pat = self.pat_cf_break(try_span, residual_local); + self.arm(break_pat, ret_expr) }; hir::ExprKind::Match( scrutinee, - arena_vec![self; err_arm, ok_arm], + arena_vec![self; break_arm, continue_arm], hir::MatchSource::TryDesugar, ) } diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 740dfc65df8..0ff1efd8165 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -31,7 +31,6 @@ //! in the HIR, especially for multiple identifiers. #![feature(crate_visibility_modifier)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(box_patterns)] #![feature(iter_zip)] #![recursion_limit = "256"] @@ -44,7 +43,7 @@ use rustc_ast::walk_list; use rustc_ast::{self as ast, *}; use rustc_ast_pretty::pprust; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_errors::{struct_span_err, Applicability}; use rustc_hir as hir; @@ -199,7 +198,7 @@ pub trait ResolverAstLowering { fn next_node_id(&mut self) -> NodeId; - fn trait_map(&self) -> &NodeMap<Vec<hir::TraitCandidate>>; + fn take_trait_map(&mut self) -> NodeMap<Vec<hir::TraitCandidate>>; fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId>; @@ -332,7 +331,7 @@ pub fn lower_crate<'a, 'hir>( lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, in_scope_lifetimes: Vec::new(), - allow_try_trait: Some([sym::try_trait][..].into()), + allow_try_trait: Some([sym::control_flow_enum, sym::try_trait_v2][..].into()), allow_gen_future: Some([sym::gen_future][..].into()), } .lower_crate(krate) @@ -502,14 +501,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let proc_macros = c.proc_macros.iter().map(|id| self.node_id_to_hir_id[*id].unwrap()).collect(); - let trait_map = self - .resolver - .trait_map() - .iter() - .filter_map(|(&k, v)| { - self.node_id_to_hir_id.get(k).and_then(|id| id.as_ref()).map(|id| (*id, v.clone())) - }) - .collect(); + let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); + for (k, v) in self.resolver.take_trait_map().into_iter() { + if let Some(Some(hir_id)) = self.node_id_to_hir_id.get(k) { + let map = trait_map.entry(hir_id.owner).or_default(); + map.insert(hir_id.local_id, v.into_boxed_slice()); + } + } let mut def_id_to_hir_id = IndexVec::default(); @@ -2490,14 +2488,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { self.pat(span, hir::PatKind::Lit(expr)) } - fn pat_ok(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { + fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { let field = self.single_pat_field(span, pat); - self.pat_lang_item_variant(span, hir::LangItem::ResultOk, field) + self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field) } - fn pat_err(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { + fn pat_cf_break(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { let field = self.single_pat_field(span, pat); - self.pat_lang_item_variant(span, hir::LangItem::ResultErr, field) + self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field) } fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 4215d5c55a0..4996c2195ef 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -713,10 +713,6 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(half_open_range_patterns, "half-open range patterns are unstable"); gate_all!(inline_const, "inline-const is experimental"); gate_all!( - extended_key_value_attributes, - "arbitrary expressions in key-value attributes are unstable" - ); - gate_all!( const_generics_defaults, "default values for const generic parameters are experimental" ); diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index c9e2d202da9..26da18b571c 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -6,7 +6,6 @@ #![feature(bindings_after_at)] #![feature(iter_is_partitioned)] -#![feature(box_syntax)] #![feature(box_patterns)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ast_pretty/src/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs index 67b66284f66..6bd543ff150 100644 --- a/compiler/rustc_ast_pretty/src/lib.rs +++ b/compiler/rustc_ast_pretty/src/lib.rs @@ -1,6 +1,5 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(box_patterns)] #![recursion_limit = "256"] diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index da9d89745a8..b7bb896f318 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -955,12 +955,12 @@ impl<'a> State<'a> { self.pclose(); } ast::TyKind::AnonymousStruct(ref fields, ..) => { - self.s.word("struct"); - self.print_record_struct_body(fields, ty.span); + self.head("struct"); + self.print_record_struct_body(&fields, ty.span); } ast::TyKind::AnonymousUnion(ref fields, ..) => { - self.s.word("union"); - self.print_record_struct_body(fields, ty.span); + self.head("union"); + self.print_record_struct_body(&fields, ty.span); } ast::TyKind::Paren(ref typ) => { self.popen(); @@ -1397,12 +1397,7 @@ impl<'a> State<'a> { } } - crate fn print_record_struct_body( - &mut self, - fields: &Vec<ast::FieldDef>, - span: rustc_span::Span, - ) { - self.nbsp(); + crate fn print_record_struct_body(&mut self, fields: &[ast::FieldDef], span: rustc_span::Span) { self.bopen(); self.hardbreak_if_not_bol(); @@ -1451,6 +1446,7 @@ impl<'a> State<'a> { } ast::VariantData::Struct(ref fields, ..) => { self.print_where_clause(&generics.where_clause); + self.nbsp(); self.print_record_struct_body(fields, span); } } diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index ab68d24e4b3..3fb11f77872 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -4,8 +4,6 @@ //! The goal is to move the definition of `MetaItem` and things that don't need to be in `syntax` //! to this crate. -#![cfg_attr(bootstrap, feature(or_patterns))] - #[macro_use] extern crate rustc_macros; diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 17b7793c7dd..2393e0b9ebf 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -9,7 +9,6 @@ #![feature(decl_macro)] #![feature(iter_zip)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] #![recursion_limit = "256"] diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock index e6792def567..a6f5925149b 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/Cargo.lock @@ -26,12 +26,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] -name = "byteorder" -version = "1.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" - -[[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -39,18 +33,17 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.73.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" +version = "0.74.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.73.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" +version = "0.74.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" dependencies = [ - "byteorder", "cranelift-bforest", "cranelift-codegen-meta", "cranelift-codegen-shared", @@ -60,13 +53,12 @@ dependencies = [ "regalloc", "smallvec", "target-lexicon", - "thiserror", ] [[package]] name = "cranelift-codegen-meta" -version = "0.73.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" +version = "0.74.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" dependencies = [ "cranelift-codegen-shared", "cranelift-entity", @@ -74,18 +66,18 @@ dependencies = [ [[package]] name = "cranelift-codegen-shared" -version = "0.73.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" +version = "0.74.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" [[package]] name = "cranelift-entity" -version = "0.73.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" +version = "0.74.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" [[package]] name = "cranelift-frontend" -version = "0.73.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" +version = "0.74.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" dependencies = [ "cranelift-codegen", "log", @@ -95,15 +87,14 @@ dependencies = [ [[package]] name = "cranelift-jit" -version = "0.73.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" +version = "0.74.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" dependencies = [ "anyhow", "cranelift-codegen", "cranelift-entity", "cranelift-module", "cranelift-native", - "errno", "libc", "log", "region", @@ -113,20 +104,19 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.73.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" +version = "0.74.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" dependencies = [ "anyhow", "cranelift-codegen", "cranelift-entity", "log", - "thiserror", ] [[package]] name = "cranelift-native" -version = "0.73.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" +version = "0.74.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" dependencies = [ "cranelift-codegen", "target-lexicon", @@ -134,8 +124,8 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.73.0" -source = "git+https://github.com/bytecodealliance/wasmtime/?branch=main#45bee40f338c631bff4a799288101ba328c7ad36" +version = "0.74.0" +source = "git+https://github.com/bytecodealliance/wasmtime.git?branch=main#76c6b83f6a21a12a11d4f890490f8acb6329a600" dependencies = [ "anyhow", "cranelift-codegen", @@ -155,37 +145,10 @@ dependencies = [ ] [[package]] -name = "errno" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa68f2fb9cae9d37c9b2b3584aba698a2e97f72d7aef7b9f7aa71d8b54ce46fe" -dependencies = [ - "errno-dragonfly", - "libc", - "winapi", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" -dependencies = [ - "gcc", - "libc", -] - -[[package]] -name = "gcc" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" - -[[package]] name = "gimli" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" +checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189" dependencies = [ "indexmap", ] @@ -242,33 +205,15 @@ dependencies = [ [[package]] name = "object" -version = "0.23.0" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" +checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170" dependencies = [ "crc32fast", "indexmap", ] [[package]] -name = "proc-macro2" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "quote" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" -dependencies = [ - "proc-macro2", -] - -[[package]] name = "regalloc" version = "0.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -323,49 +268,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] -name = "syn" -version = "1.0.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c700597eca8a5a762beb35753ef6b94df201c81cca676604f547495a0d7f0081" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] name = "target-lexicon" version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ae3b39281e4b14b8123bdbaddd472b7dfe215e444181f2f9d2443c2444f834" [[package]] -name = "thiserror" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] name = "winapi" version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml index 2789207c655..fd149af4547 100644 --- a/compiler/rustc_codegen_cranelift/Cargo.toml +++ b/compiler/rustc_codegen_cranelift/Cargo.toml @@ -9,15 +9,15 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", features = ["unwind"] } -cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } -cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } -cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } -cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main", optional = true } -cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime/", branch = "main" } +cranelift-codegen = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", features = ["unwind"] } +cranelift-frontend = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" } +cranelift-module = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" } +cranelift-native = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" } +cranelift-jit = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main", optional = true } +cranelift-object = { git = "https://github.com/bytecodealliance/wasmtime.git", branch = "main" } target-lexicon = "0.12.0" -gimli = { version = "0.23.0", default-features = false, features = ["write"]} -object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } +gimli = { version = "0.24.0", default-features = false, features = ["write"]} +object = { version = "0.24.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } ar = { git = "https://github.com/bjorn3/rust-ar.git", branch = "do_not_remove_cg_clif_ranlib" } indexmap = "1.0.2" @@ -25,11 +25,11 @@ libloading = { version = "0.6.0", optional = true } smallvec = "1.6.1" # Uncomment to use local checkout of cranelift -#[patch."https://github.com/bytecodealliance/wasmtime/"] +#[patch."https://github.com/bytecodealliance/wasmtime.git"] #cranelift-codegen = { path = "../wasmtime/cranelift/codegen" } #cranelift-frontend = { path = "../wasmtime/cranelift/frontend" } #cranelift-module = { path = "../wasmtime/cranelift/module" } -#cranelift-native = { path = ../wasmtime/cranelift/native" } +#cranelift-native = { path = "../wasmtime/cranelift/native" } #cranelift-jit = { path = "../wasmtime/cranelift/jit" } #cranelift-object = { path = "../wasmtime/cranelift/object" } @@ -70,13 +70,5 @@ debug = false opt-level = 0 debug = false -[profile.dev.package.syn] -opt-level = 0 -debug = false - -[profile.release.package.syn] -opt-level = 0 -debug = false - [package.metadata.rust-analyzer] rustc_private = true diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock index e058a972ead..923deb9aec4 100644 --- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock +++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock @@ -40,9 +40,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "cc" -version = "1.0.67" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" +checksum = "4a72c244c1ff497a746a7e1fb3d14bd08420ecda70c8f25c7112f2781652d787" [[package]] name = "cfg-if" @@ -56,7 +56,7 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.40" +version = "0.1.43" dependencies = [ "rustc-std-workspace-core", ] @@ -132,9 +132,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.94" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18794a8ad5b29321f790b55d93dfba91e125cb1a9edbd4f8e3150acc771c1a5e" +checksum = "789da6d93f1b866ffe175afc5322a4d76c038605a1c3319bb57b06967ca98a36" dependencies = [ "rustc-std-workspace-core", ] @@ -195,9 +195,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" +checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh index f7fcef10774..54b7a94750c 100755 --- a/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh +++ b/compiler/rustc_codegen_cranelift/build_sysroot/prepare_sysroot_src.sh @@ -32,7 +32,7 @@ popd git clone https://github.com/rust-lang/compiler-builtins.git || echo "rust-lang/compiler-builtins has already been cloned" pushd compiler-builtins git checkout -- . -git checkout 0.1.40 +git checkout 0.1.43 git apply ../../crate_patches/000*-compiler-builtins-*.patch popd diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0002-compiler-builtins-Disable-128bit-atomic-operations.patch b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Disable-128bit-atomic-operations.patch index 7daea99f579..7daea99f579 100644 --- a/compiler/rustc_codegen_cranelift/crate_patches/0002-compiler-builtins-Disable-128bit-atomic-operations.patch +++ b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Disable-128bit-atomic-operations.patch diff --git a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch b/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch deleted file mode 100644 index b4acc4f5b73..00000000000 --- a/compiler/rustc_codegen_cranelift/crate_patches/0001-compiler-builtins-Remove-rotate_left-from-Int.patch +++ /dev/null @@ -1,35 +0,0 @@ -From 7078cca3cb614e1e82da428380b4e16fc3afef46 Mon Sep 17 00:00:00 2001 -From: bjorn3 <bjorn3@users.noreply.github.com> -Date: Thu, 21 Jan 2021 14:46:36 +0100 -Subject: [PATCH] Remove rotate_left from Int - ---- - src/int/mod.rs | 5 ----- - 1 file changed, 5 deletions(-) - -diff --git a/src/int/mod.rs b/src/int/mod.rs -index 06054c8..3bea17b 100644 ---- a/src/int/mod.rs -+++ b/src/int/mod.rs -@@ -85,7 +85,6 @@ pub trait Int: - fn wrapping_sub(self, other: Self) -> Self; - fn wrapping_shl(self, other: u32) -> Self; - fn wrapping_shr(self, other: u32) -> Self; -- fn rotate_left(self, other: u32) -> Self; - fn overflowing_add(self, other: Self) -> (Self, bool); - fn leading_zeros(self) -> u32; - } -@@ -209,10 +208,6 @@ macro_rules! int_impl_common { - <Self>::wrapping_shr(self, other) - } - -- fn rotate_left(self, other: u32) -> Self { -- <Self>::rotate_left(self, other) -- } -- - fn overflowing_add(self, other: Self) -> (Self, bool) { - <Self>::overflowing_add(self, other) - } --- -2.26.2.7.g19db9cfb68 - diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs index 77ba72df8ef..7d608df9253 100644 --- a/compiler/rustc_codegen_cranelift/example/std_example.rs +++ b/compiler/rustc_codegen_cranelift/example/std_example.rs @@ -187,20 +187,6 @@ unsafe fn test_mm_slli_si128() { ); let r = _mm_slli_si128(a, 16); assert_eq_m128i(r, _mm_set1_epi8(0)); - - #[rustfmt::skip] - let a = _mm_setr_epi8( - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - ); - let r = _mm_slli_si128(a, -1); - assert_eq_m128i(_mm_set1_epi8(0), r); - - #[rustfmt::skip] - let a = _mm_setr_epi8( - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - ); - let r = _mm_slli_si128(a, -0x80000000); - assert_eq_m128i(r, _mm_set1_epi8(0)); } #[cfg(target_arch = "x86_64")] @@ -295,7 +281,7 @@ unsafe fn test_mm_extract_epi8() { 8, 9, 10, 11, 12, 13, 14, 15 ); let r1 = _mm_extract_epi8(a, 0); - let r2 = _mm_extract_epi8(a, 19); + let r2 = _mm_extract_epi8(a, 3); assert_eq!(r1, 0xFF); assert_eq!(r2, 3); } diff --git a/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch b/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch index 8cfffe580a1..ba0eaacd828 100644 --- a/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch +++ b/compiler/rustc_codegen_cranelift/patches/0022-core-Disable-not-compiling-tests.patch @@ -39,46 +39,6 @@ index a35897e..f0bf645 100644 pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded { match decode(v).1 { -diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs -index 0475aeb..9558198 100644 ---- a/library/core/tests/num/int_macros.rs -+++ b/library/core/tests/num/int_macros.rs -@@ -88,6 +88,7 @@ mod tests { - assert_eq!(x.trailing_ones(), 0); - } - -+ /* - #[test] - fn test_rotate() { - assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); -@@ -112,6 +113,7 @@ mod tests { - assert_eq!(B.rotate_left(128), B); - assert_eq!(C.rotate_left(128), C); - } -+ */ - - #[test] - fn test_swap_bytes() { -diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs -index 04ed14f..a6e372e 100644 ---- a/library/core/tests/num/uint_macros.rs -+++ b/library/core/tests/num/uint_macros.rs -@@ -52,6 +52,7 @@ mod tests { - assert_eq!(x.trailing_ones(), 0); - } - -+ /* - #[test] - fn test_rotate() { - assert_eq!(A.rotate_left(6).rotate_right(2).rotate_right(4), A); -@@ -76,6 +77,7 @@ mod tests { - assert_eq!(B.rotate_left(128), B); - assert_eq!(C.rotate_left(128), C); - } -+ */ - - #[test] - fn test_swap_bytes() { diff --git a/library/core/tests/ptr.rs b/library/core/tests/ptr.rs index 1a6be3a..42dbd59 100644 --- a/library/core/tests/ptr.rs diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain index 5442e3345aa..9fe6e093a7b 100644 --- a/compiler/rustc_codegen_cranelift/rust-toolchain +++ b/compiler/rustc_codegen_cranelift/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-04-28" +channel = "nightly-2021-05-26" components = ["rust-src", "rustc-dev", "llvm-tools-preview"] diff --git a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh index 4821a07ac5d..43c4887669c 100644 --- a/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh +++ b/compiler/rustc_codegen_cranelift/scripts/setup_rust_fork.sh @@ -24,18 +24,6 @@ index 5bd1147cad5..10d68a2ff14 100644 + [patch."https://github.com/rust-lang/rust-clippy"] clippy_lints = { path = "src/tools/clippy/clippy_lints" } -diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml -index 23e689fcae7..5f077b765b6 100644 ---- a/compiler/rustc_data_structures/Cargo.toml -+++ b/compiler/rustc_data_structures/Cargo.toml -@@ -32,7 +32,6 @@ tempfile = "3.0.5" - - [dependencies.parking_lot] - version = "0.11" --features = ["nightly"] - - [target.'cfg(windows)'.dependencies] - winapi = { version = "0.3", features = ["fileapi", "psapi"] } diff --git a/library/alloc/Cargo.toml b/library/alloc/Cargo.toml index d95b5b7f17f..00b6f0e3635 100644 --- a/library/alloc/Cargo.toml @@ -44,11 +32,12 @@ index d95b5b7f17f..00b6f0e3635 100644 [dependencies] core = { path = "../core" } --compiler_builtins = { version = "0.1.39", features = ['rustc-dep-of-std'] } -+compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std', 'no-asm'] } +-compiler_builtins = { version = "0.1.40", features = ['rustc-dep-of-std'] } ++compiler_builtins = { version = "0.1.43", features = ['rustc-dep-of-std', 'no-asm'] } [dev-dependencies] rand = "0.7" + rand_xorshift = "0.2" EOF cat > config.toml <<EOF diff --git a/compiler/rustc_codegen_cranelift/scripts/tests.sh b/compiler/rustc_codegen_cranelift/scripts/tests.sh index 3afcea8f06b..0d99d2c507c 100755 --- a/compiler/rustc_codegen_cranelift/scripts/tests.sh +++ b/compiler/rustc_codegen_cranelift/scripts/tests.sh @@ -116,6 +116,7 @@ function extended_sysroot_tests() { pushd regex echo "[TEST] rust-lang/regex example shootout-regex-dna" cargo clean + export RUSTFLAGS="$RUSTFLAGS --cap-lints warn" # newer aho_corasick versions throw a deprecation warning # Make sure `[codegen mono items] start` doesn't poison the diff ../build/cargo.sh build --example shootout-regex-dna --target $TARGET_TRIPLE if [[ "$HOST_TRIPLE" = "$TARGET_TRIPLE" ]]; then diff --git a/compiler/rustc_codegen_cranelift/src/archive.rs b/compiler/rustc_codegen_cranelift/src/archive.rs index fc0823302e0..bd54adc53ee 100644 --- a/compiler/rustc_codegen_cranelift/src/archive.rs +++ b/compiler/rustc_codegen_cranelift/src/archive.rs @@ -160,7 +160,7 @@ impl<'a> ArchiveBuilder<'a> for ArArchiveBuilder<'a> { }; if !self.no_builtin_ranlib { - match object::File::parse(&data) { + match object::File::parse(&*data) { Ok(object) => { symbol_table.insert( entry_name.as_bytes().to_vec(), diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 3ec5c14ff17..ec3e17e5b75 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -110,11 +110,6 @@ pub(crate) fn codegen_fn<'tcx>( // Verify function verify_func(tcx, &clif_comments, &context.func); - // Perform rust specific optimizations - tcx.sess.time("optimize clif ir", || { - crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments); - }); - // If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128` // instruction, which doesn't have an encoding. context.compute_cfg(); @@ -125,10 +120,14 @@ pub(crate) fn codegen_fn<'tcx>( // invalidate it when it would change. context.domtree.clear(); - context.want_disasm = crate::pretty_clif::should_write_ir(tcx); + // Perform rust specific optimizations + tcx.sess.time("optimize clif ir", || { + crate::optimize::optimize_function(tcx, instance, context, &mut clif_comments); + }); // Define function tcx.sess.time("define function", || { + context.want_disasm = crate::pretty_clif::should_write_ir(tcx); module .define_function(func_id, context, &mut NullTrapSink {}, &mut NullStackMapSink {}) .unwrap() @@ -870,7 +869,7 @@ pub(crate) fn codegen_operand<'tcx>( pub(crate) fn codegen_panic<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, msg_str: &str, span: Span) { let location = fx.get_caller_location(span).load_scalar(fx); - let msg_ptr = fx.anonymous_str("assert", msg_str); + let msg_ptr = fx.anonymous_str(msg_str); let msg_len = fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(msg_str.len()).unwrap()); let args = [msg_ptr, msg_len, location]; diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs index c12d6d0f141..488ff6e1349 100644 --- a/compiler/rustc_codegen_cranelift/src/common.rs +++ b/compiler/rustc_codegen_cranelift/src/common.rs @@ -347,19 +347,10 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> { self.module.isa().triple() } - pub(crate) fn anonymous_str(&mut self, prefix: &str, msg: &str) -> Value { - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; - - let mut hasher = DefaultHasher::new(); - msg.hash(&mut hasher); - let msg_hash = hasher.finish(); + pub(crate) fn anonymous_str(&mut self, msg: &str) -> Value { let mut data_ctx = DataContext::new(); data_ctx.define(msg.as_bytes().to_vec().into_boxed_slice()); - let msg_id = self - .module - .declare_data(&format!("__{}_{:08x}", prefix, msg_hash), Linkage::Local, false, false) - .unwrap(); + let msg_id = self.module.declare_anonymous_data(false, false).unwrap(); // Ignore DuplicateDefinition error, as the data will be the same let _ = self.module.define_data(msg_id, &data_ctx); diff --git a/compiler/rustc_codegen_cranelift/src/config.rs b/compiler/rustc_codegen_cranelift/src/config.rs index e59a0cb0a23..eef3c8c8d6e 100644 --- a/compiler/rustc_codegen_cranelift/src/config.rs +++ b/compiler/rustc_codegen_cranelift/src/config.rs @@ -48,6 +48,12 @@ pub struct BackendConfig { /// Can be set using `-Cllvm-args=display_cg_time=...`. pub display_cg_time: bool, + /// The register allocator to use. + /// + /// Defaults to the value of `CG_CLIF_REGALLOC` or `backtracking` otherwise. Can be set using + /// `-Cllvm-args=regalloc=...`. + pub regalloc: String, + /// Enable the Cranelift ir verifier for all compilation passes. If not set it will only run /// once before passing the clif ir to Cranelift for compilation. /// @@ -74,6 +80,8 @@ impl Default for BackendConfig { args.split(' ').map(|arg| arg.to_string()).collect() }, display_cg_time: bool_env_var("CG_CLIF_DISPLAY_CG_TIME"), + regalloc: std::env::var("CG_CLIF_REGALLOC") + .unwrap_or_else(|_| "backtracking".to_string()), enable_verifier: cfg!(debug_assertions) || bool_env_var("CG_CLIF_ENABLE_VERIFIER"), disable_incr_cache: bool_env_var("CG_CLIF_DISABLE_INCR_CACHE"), } @@ -93,6 +101,7 @@ impl BackendConfig { match name { "mode" => config.codegen_mode = value.parse()?, "display_cg_time" => config.display_cg_time = parse_bool(name, value)?, + "regalloc" => config.regalloc = value.to_string(), "enable_verifier" => config.enable_verifier = parse_bool(name, value)?, "disable_incr_cache" => config.disable_incr_cache = parse_bool(name, value)?, _ => return Err(format!("Unknown option `{}`", name)), diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs index 0a0e02d2639..3ba12c4e96d 100644 --- a/compiler/rustc_codegen_cranelift/src/constant.rs +++ b/compiler/rustc_codegen_cranelift/src/constant.rs @@ -2,11 +2,13 @@ use rustc_span::DUMMY_SP; +use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::ErrorReported; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{ - read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Pointer, Scalar, + alloc_range, read_target_uint, AllocId, Allocation, ConstValue, ErrorHandled, GlobalAlloc, + Scalar, }; use rustc_middle::ty::ConstKind; @@ -175,9 +177,9 @@ pub(crate) fn codegen_const_value<'tcx>( let mut alloc = Allocation::from_bytes( std::iter::repeat(0).take(size.bytes_usize()).collect::<Vec<u8>>(), align, + Mutability::Not, ); - let ptr = Pointer::new(AllocId(!0), Size::ZERO); // The alloc id is never used - alloc.write_scalar(fx, ptr, x.into(), size).unwrap(); + alloc.write_scalar(fx, alloc_range(Size::ZERO, size), x.into()).unwrap(); let alloc = fx.tcx.intern_const_alloc(alloc); return CValue::by_ref(pointer_for_allocation(fx, alloc), layout); } @@ -374,8 +376,19 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant data_ctx.set_align(alloc.align.bytes()); if let Some(section_name) = section_name { - // FIXME set correct segment for Mach-O files - data_ctx.set_segment_section("", &*section_name); + let (segment_name, section_name) = if tcx.sess.target.is_like_osx { + if let Some(names) = section_name.split_once(',') { + names + } else { + tcx.sess.fatal(&format!( + "#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma", + section_name + )); + } + } else { + ("", &*section_name) + }; + data_ctx.set_segment_section(segment_name, section_name); } let bytes = alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()).to_vec(); @@ -437,12 +450,89 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( operand: &Operand<'tcx>, ) -> Option<ConstValue<'tcx>> { match operand { - Operand::Copy(_) | Operand::Move(_) => None, Operand::Constant(const_) => match const_.literal { ConstantKind::Ty(const_) => { fx.monomorphize(const_).eval(fx.tcx, ParamEnv::reveal_all()).val.try_to_value() } ConstantKind::Val(val, _) => Some(val), }, + // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored + // inside a temporary before being passed to the intrinsic requiring the const argument. + // This code tries to find a single constant defining definition of the referenced local. + Operand::Copy(place) | Operand::Move(place) => { + if !place.projection.is_empty() { + return None; + } + let mut computed_const_val = None; + for bb_data in fx.mir.basic_blocks() { + for stmt in &bb_data.statements { + match &stmt.kind { + StatementKind::Assign(local_and_rvalue) if &local_and_rvalue.0 == place => { + match &local_and_rvalue.1 { + Rvalue::Cast(CastKind::Misc, operand, ty) => { + if computed_const_val.is_some() { + return None; // local assigned twice + } + if !matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) { + return None; + } + let const_val = mir_operand_get_const_val(fx, operand)?; + if fx.layout_of(ty).size + != const_val.try_to_scalar_int()?.size() + { + return None; + } + computed_const_val = Some(const_val); + } + Rvalue::Use(operand) => { + computed_const_val = mir_operand_get_const_val(fx, operand) + } + _ => return None, + } + } + StatementKind::SetDiscriminant { place: stmt_place, variant_index: _ } + if &**stmt_place == place => + { + return None; + } + StatementKind::LlvmInlineAsm(_) | StatementKind::CopyNonOverlapping(_) => { + return None; + } // conservative handling + StatementKind::Assign(_) + | StatementKind::FakeRead(_) + | StatementKind::SetDiscriminant { .. } + | StatementKind::StorageLive(_) + | StatementKind::StorageDead(_) + | StatementKind::Retag(_, _) + | StatementKind::AscribeUserType(_, _) + | StatementKind::Coverage(_) + | StatementKind::Nop => {} + } + } + match &bb_data.terminator().kind { + TerminatorKind::Goto { .. } + | TerminatorKind::SwitchInt { .. } + | TerminatorKind::Resume + | TerminatorKind::Abort + | TerminatorKind::Return + | TerminatorKind::Unreachable + | TerminatorKind::Drop { .. } + | TerminatorKind::Assert { .. } => {} + TerminatorKind::DropAndReplace { .. } + | TerminatorKind::Yield { .. } + | TerminatorKind::GeneratorDrop + | TerminatorKind::FalseEdge { .. } + | TerminatorKind::FalseUnwind { .. } => unreachable!(), + TerminatorKind::InlineAsm { .. } => return None, + TerminatorKind::Call { destination: Some((call_place, _)), .. } + if call_place == place => + { + return None; + } + TerminatorKind::Call { .. } => {} + } + } + computed_const_val + } } } diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 24d933728db..9cf51d15c8c 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -73,9 +73,8 @@ fn reuse_workproduct_for_cgu( let mut object = None; let work_product = cgu.work_product(tcx); if let Some(saved_file) = &work_product.saved_file { - let obj_out = tcx - .output_filenames(()) - .temp_path(OutputType::Object, Some(&cgu.name().as_str())); + let obj_out = + tcx.output_filenames(()).temp_path(OutputType::Object, Some(&cgu.name().as_str())); object = Some(obj_out.clone()); let source_file = rustc_incremental::in_incr_comp_dir(&incr_comp_session_dir, &saved_file); if let Err(err) = rustc_fs_util::link_or_copy(&source_file, &obj_out) { @@ -145,7 +144,13 @@ fn module_codegen( } } } - crate::main_shim::maybe_create_entry_wrapper(tcx, &mut module, &mut cx.unwind_context, false); + crate::main_shim::maybe_create_entry_wrapper( + tcx, + &mut module, + &mut cx.unwind_context, + false, + cgu.is_primary(), + ); let debug_context = cx.debug_context; let unwind_context = cx.unwind_context; @@ -275,9 +280,8 @@ pub(crate) fn run_aot( .as_str() .to_string(); - let tmp_file = tcx - .output_filenames(()) - .temp_path(OutputType::Metadata, Some(&metadata_cgu_name)); + let tmp_file = + tcx.output_filenames(()).temp_path(OutputType::Metadata, Some(&metadata_cgu_name)); let obj = crate::backend::with_object(tcx.sess, &metadata_cgu_name, |object| { crate::metadata::write_metadata(tcx, object); @@ -352,8 +356,7 @@ fn codegen_global_asm(tcx: TyCtxt<'_>, cgu_name: &str, global_asm: &str) { .collect::<Vec<_>>() .join("\n"); - let output_object_file = - tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name)); + let output_object_file = tcx.output_filenames(()).temp_path(OutputType::Object, Some(cgu_name)); // Assemble `global_asm` let global_asm_object_file = add_file_stem_postfix(output_object_file.clone(), ".asm"); diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs index 632e86da736..4a99cb727c8 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs @@ -45,6 +45,7 @@ fn create_jit_module<'tcx>( &mut jit_module, &mut cx.unwind_context, true, + true, ); (jit_module, cx) @@ -206,7 +207,7 @@ fn load_imported_symbols_for_jit(tcx: TyCtxt<'_>) -> Vec<(String, *const u8)> { use object::{Object, ObjectSymbol}; let lib = libloading::Library::new(&path).unwrap(); let obj = std::fs::read(path).unwrap(); - let obj = object::File::parse(&obj).unwrap(); + let obj = object::File::parse(&*obj).unwrap(); imported_symbols.extend(obj.dynamic_symbols().filter_map(|symbol| { let name = symbol.name().unwrap().to_string(); if name.is_empty() || !symbol.is_global() || symbol.is_undefined() { diff --git a/compiler/rustc_codegen_cranelift/src/inline_asm.rs b/compiler/rustc_codegen_cranelift/src/inline_asm.rs index 4ab4c2957ca..09c5e6031c7 100644 --- a/compiler/rustc_codegen_cranelift/src/inline_asm.rs +++ b/compiler/rustc_codegen_cranelift/src/inline_asm.rs @@ -24,14 +24,22 @@ pub(crate) fn codegen_inline_asm<'tcx>( let true_ = fx.bcx.ins().iconst(types::I32, 1); fx.bcx.ins().trapnz(true_, TrapCode::User(1)); return; - } else if template[0] == InlineAsmTemplatePiece::String("mov rsi, rbx".to_string()) - && template[1] == InlineAsmTemplatePiece::String("\n".to_string()) - && template[2] == InlineAsmTemplatePiece::String("cpuid".to_string()) - && template[3] == InlineAsmTemplatePiece::String("\n".to_string()) - && template[4] == InlineAsmTemplatePiece::String("xchg rsi, rbx".to_string()) + } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string()) + && matches!( + template[1], + InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ } + ) + && template[2] == InlineAsmTemplatePiece::String("\n".to_string()) + && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string()) + && template[4] == InlineAsmTemplatePiece::String("\n".to_string()) + && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string()) + && matches!( + template[6], + InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ } + ) { assert_eq!(operands.len(), 4); - let (leaf, eax_place) = match operands[0] { + let (leaf, eax_place) = match operands[1] { InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => { let reg = expect_reg(reg); assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::ax)); @@ -42,10 +50,14 @@ pub(crate) fn codegen_inline_asm<'tcx>( } _ => unreachable!(), }; - let ebx_place = match operands[1] { + let ebx_place = match operands[0] { InlineAsmOperand::Out { reg, late: true, place } => { - let reg = expect_reg(reg); - assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::si)); + assert_eq!( + reg, + InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86( + X86InlineAsmRegClass::reg + )) + ); crate::base::codegen_place(fx, place.unwrap()) } _ => unreachable!(), diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs index 9de12e759bc..d02dfd93c3e 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/cpuid.rs @@ -12,6 +12,7 @@ pub(crate) fn codegen_cpuid_call<'tcx>( ) -> (Value, Value, Value, Value) { let leaf_0 = fx.bcx.create_block(); let leaf_1 = fx.bcx.create_block(); + let leaf_7 = fx.bcx.create_block(); let leaf_8000_0000 = fx.bcx.create_block(); let leaf_8000_0001 = fx.bcx.create_block(); let unsupported_leaf = fx.bcx.create_block(); @@ -25,6 +26,7 @@ pub(crate) fn codegen_cpuid_call<'tcx>( let mut switch = cranelift_frontend::Switch::new(); switch.set_entry(0, leaf_0); switch.set_entry(1, leaf_1); + switch.set_entry(7, leaf_7); switch.set_entry(0x8000_0000, leaf_8000_0000); switch.set_entry(0x8000_0001, leaf_8000_0001); switch.emit(&mut fx.bcx, leaf, unsupported_leaf); @@ -43,6 +45,11 @@ pub(crate) fn codegen_cpuid_call<'tcx>( let edx_features = fx.bcx.ins().iconst(types::I32, 1 << 25 /* sse */ | 1 << 26 /* sse2 */); fx.bcx.ins().jump(dest, &[cpu_signature, additional_information, ecx_features, edx_features]); + fx.bcx.switch_to_block(leaf_7); + // This leaf technically has subleaves, but we just return zero for all subleaves. + let zero = fx.bcx.ins().iconst(types::I32, 0); + fx.bcx.ins().jump(dest, &[zero, zero, zero, zero]); + fx.bcx.switch_to_block(leaf_8000_0000); let extended_max_basic_leaf = fx.bcx.ins().iconst(types::I32, 0); let zero = fx.bcx.ins().iconst(types::I32, 0); diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs index 435737f3a51..52896fc7127 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs @@ -8,8 +8,8 @@ mod simd; pub(crate) use cpuid::codegen_cpuid_call; pub(crate) use llvm::codegen_llvm_intrinsic_call; -use rustc_span::symbol::{sym, kw}; use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_span::symbol::{kw, sym}; use crate::prelude::*; use cranelift_codegen::ir::AtomicRmwOp; diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs index 940d2514f74..c2f469fa021 100644 --- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs +++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs @@ -86,9 +86,8 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( let idx_bytes = match idx_const { ConstValue::ByRef { alloc, offset } => { - let ptr = Pointer::new(AllocId(0 /* dummy */), offset); let size = Size::from_bytes(4 * ret_lane_count /* size_of([u32; ret_lane_count]) */); - alloc.get_bytes(fx, ptr, size).unwrap() + alloc.get_bytes(fx, alloc_range(offset, size)).unwrap() } _ => unreachable!("{:?}", idx_const), }; diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs index ff6e1856059..4ee887cd5af 100644 --- a/compiler/rustc_codegen_cranelift/src/lib.rs +++ b/compiler/rustc_codegen_cranelift/src/lib.rs @@ -256,6 +256,8 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar flags_builder.set("enable_llvm_abi_extensions", "true").unwrap(); + flags_builder.set("regalloc", &backend_config.regalloc).unwrap(); + use rustc_session::config::OptLevel; match sess.opts.optimize { OptLevel::No => { @@ -277,21 +279,23 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Box<dyn isa::Tar builder } Some(value) => { - let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap(); + let mut builder = + cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap(); if let Err(_) = builder.enable(value) { sess.fatal("The specified target cpu isn't currently supported by Cranelift."); } builder } None => { - let mut builder = cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap(); + let mut builder = + cranelift_codegen::isa::lookup_variant(target_triple, variant).unwrap(); // Don't use "haswell" as the default, as it implies `has_lzcnt`. // macOS CI is still at Ivy Bridge EP, so `lzcnt` is interpreted as `bsr`. builder.enable("nehalem").unwrap(); builder } }; - + isa_builder.finish(flags) } diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs index d1958c5f96b..8fd1e4f5811 100644 --- a/compiler/rustc_codegen_cranelift/src/main_shim.rs +++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs @@ -14,6 +14,7 @@ pub(crate) fn maybe_create_entry_wrapper( module: &mut impl Module, unwind_context: &mut UnwindContext, is_jit: bool, + is_primary_cgu: bool, ) { let (main_def_id, is_main_fn) = match tcx.entry_fn(()) { Some((def_id, entry_ty)) => ( @@ -26,8 +27,12 @@ pub(crate) fn maybe_create_entry_wrapper( None => return, }; - let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx); - if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() { + if main_def_id.is_local() { + let instance = Instance::mono(tcx, main_def_id).polymorphize(tcx); + if !is_jit && module.get_name(&*tcx.symbol_name(instance).name).is_none() { + return; + } + } else if !is_primary_cgu { return; } diff --git a/compiler/rustc_codegen_cranelift/src/trap.rs b/compiler/rustc_codegen_cranelift/src/trap.rs index 819c8b51558..21d3e68dbc7 100644 --- a/compiler/rustc_codegen_cranelift/src/trap.rs +++ b/compiler/rustc_codegen_cranelift/src/trap.rs @@ -21,7 +21,7 @@ fn codegen_print(fx: &mut FunctionCx<'_, '_, '_>, msg: &str) { } let real_msg = format!("trap at {:?} ({}): {}\0", fx.instance, fx.symbol_name, msg); - let msg_ptr = fx.anonymous_str("trap", &real_msg); + let msg_ptr = fx.anonymous_str(&real_msg); fx.bcx.ins().call(puts, &[msg_ptr]); } diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs index 9a572c3501f..171f39805f8 100644 --- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs +++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs @@ -561,6 +561,7 @@ impl<'tcx> CPlace<'tcx> { dst_align, src_align, true, + MemFlags::trusted(), ); } CValueInner::ByRef(_, Some(_)) => todo!(), diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index bc9d99ed4a1..c8cf0116c64 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -69,6 +69,7 @@ impl abi::HasDataLayout for Builder<'_, '_, '_> { } impl ty::layout::HasTyCtxt<'tcx> for Builder<'_, '_, 'tcx> { + #[inline] fn tcx(&self) -> TyCtxt<'tcx> { self.cx.tcx } @@ -81,6 +82,7 @@ impl ty::layout::HasParamEnv<'tcx> for Builder<'_, '_, 'tcx> { } impl HasTargetSpec for Builder<'_, '_, 'tcx> { + #[inline] fn target_spec(&self) -> &Target { &self.cx.target_spec() } @@ -98,6 +100,7 @@ impl abi::LayoutOf for Builder<'_, '_, 'tcx> { impl Deref for Builder<'_, 'll, 'tcx> { type Target = CodegenCx<'ll, 'tcx>; + #[inline] fn deref(&self) -> &Self::Target { self.cx } diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs index b26969a5012..bb16c90cd12 100644 --- a/compiler/rustc_codegen_llvm/src/callee.rs +++ b/compiler/rustc_codegen_llvm/src/callee.rs @@ -14,7 +14,6 @@ use tracing::debug; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::{self, Instance, TypeFoldable}; -use rustc_target::spec::RelocModel; /// Codegens a reference to a fn/method item, monomorphizing and /// inlining as it goes. @@ -181,7 +180,7 @@ pub fn get_fn(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) -> &'ll Value llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); } - if cx.tcx.sess.relocation_model() == RelocModel::Static { + if cx.should_assume_dso_local(llfn, true) { llvm::LLVMRustSetDSOLocal(llfn, true); } } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index 99046839973..e50d5506e22 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -282,6 +282,12 @@ impl CodegenCx<'ll, 'tcx> { } } + unsafe { + if self.should_assume_dso_local(g, true) { + llvm::LLVMRustSetDSOLocal(g, true); + } + } + self.instances.borrow_mut().insert(instance, g); g } @@ -363,6 +369,10 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { set_global_alignment(&self, g, self.align_of(ty)); llvm::LLVMSetInitializer(g, v); + if self.should_assume_dso_local(g, true) { + llvm::LLVMRustSetDSOLocal(g, true); + } + // As an optimization, all shared statics which do not have interior // mutability are placed into read-only memory. if !is_mutable && self.type_is_freeze(ty) { diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index f5c54b11c08..6aa952462fa 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -765,18 +765,21 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> { } impl HasDataLayout for CodegenCx<'ll, 'tcx> { + #[inline] fn data_layout(&self) -> &TargetDataLayout { &self.tcx.data_layout } } impl HasTargetSpec for CodegenCx<'ll, 'tcx> { + #[inline] fn target_spec(&self) -> &Target { &self.tcx.sess.target } } impl ty::layout::HasTyCtxt<'tcx> for CodegenCx<'ll, 'tcx> { + #[inline] fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 0db6659f8e2..1e70664e64d 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -1457,7 +1457,6 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> { enum_type: Ty<'tcx>, layout: TyAndLayout<'tcx>, tag_type_metadata: Option<&'ll DIType>, - containing_scope: &'ll DIScope, common_members: Vec<Option<&'ll DIType>>, span: Span, } @@ -1486,13 +1485,9 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { _ => bug!(), }; - // This will always find the metadata in the type map. let fallback = use_enum_fallback(cx); - let self_metadata = if fallback { - self.containing_scope - } else { - type_metadata(cx, self.enum_type, self.span) - }; + // This will always find the metadata in the type map. + let self_metadata = type_metadata(cx, self.enum_type, self.span); match self.layout.variants { Variants::Single { index } => { @@ -1507,7 +1502,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, self.layout, variant_info, - NoTag, + None, self_metadata, self.span, ); @@ -1539,13 +1534,26 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { .. } => { let tag_info = if fallback { - RegularTag { + // For MSVC, we generate a union of structs for each variant with an explicit + // discriminant field roughly equivalent to the following C: + // ```c + // union enum$<{name}> { + // struct {variant 0 name} { + // tag$ variant$; + // <variant 0 fields> + // } variant0; + // <other variant structs> + // } + // ``` + // The natvis in `intrinsic.nativs` then matches on `this.variant0.variant$` to + // determine which variant is active and then displays it. + Some(DirectTag { tag_field: Field::from(tag_field), tag_type_metadata: self.tag_type_metadata.unwrap(), - } + }) } else { // This doesn't matter in this case. - NoTag + None }; variants .iter_enumerated() @@ -1574,7 +1582,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { MemberDescription { name: if fallback { - String::new() + format!("variant{}", i.as_u32()) } else { variant_info.variant_name() }, @@ -1599,77 +1607,135 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { ref variants, tag_field, } => { + let calculate_niche_value = |i: VariantIdx| { + if i == dataful_variant { + None + } else { + let value = (i.as_u32() as u128) + .wrapping_sub(niche_variants.start().as_u32() as u128) + .wrapping_add(niche_start); + let value = tag.value.size(cx).truncate(value); + // NOTE(eddyb) do *NOT* remove this assert, until + // we pass the full 128-bit value to LLVM, otherwise + // truncation will be silent and remain undetected. + assert_eq!(value as u64 as u128, value); + Some(value as u64) + } + }; + + // For MSVC, we will generate a union of two fields, one for the dataful variant + // and one that just points to the discriminant. We also create an enum that + // contains tag values for the non-dataful variants and make the discriminant field + // that type. We then use natvis to render the enum type correctly in Windbg/VS. + // This will generate debuginfo roughly equivalent to the following C: + // ```c + // union enum$<{name}, {min niche}, {max niche}, {dataful variant name}> { + // struct <dataful variant name> { + // <fields in dataful variant> + // } dataful_variant; + // enum Discriminant$ { + // <non-dataful variants> + // } discriminant; + // } + // ``` + // The natvis in `intrinsic.natvis` matches on the type name `enum$<*, *, *, *>` + // and evaluates `this.discriminant`. If the value is between the min niche and max + // niche, then the enum is in the dataful variant and `this.dataful_variant` is + // rendered. Otherwise, the enum is in one of the non-dataful variants. In that + // case, we just need to render the name of the `this.discriminant` enum. if fallback { - let variant = self.layout.for_variant(cx, dataful_variant); - // Create a description of the non-null variant. - let (variant_type_metadata, member_description_factory) = describe_enum_variant( + let dataful_variant_layout = self.layout.for_variant(cx, dataful_variant); + + let mut discr_enum_ty = tag.value.to_ty(cx.tcx); + // If the niche is the NULL value of a reference, then `discr_enum_ty` will be a RawPtr. + // CodeView doesn't know what to do with enums whose base type is a pointer so we fix this up + // to just be `usize`. + if let ty::RawPtr(_) = discr_enum_ty.kind() { + discr_enum_ty = cx.tcx.types.usize; + } + + let tags: Vec<_> = variants + .iter_enumerated() + .filter_map(|(variant_idx, _)| { + calculate_niche_value(variant_idx).map(|tag| { + let variant = variant_info_for(variant_idx); + let name = variant.variant_name(); + + Some(unsafe { + llvm::LLVMRustDIBuilderCreateEnumerator( + DIB(cx), + name.as_ptr().cast(), + name.len(), + tag as i64, + !discr_enum_ty.is_signed(), + ) + }) + }) + }) + .collect(); + + let discr_enum = unsafe { + llvm::LLVMRustDIBuilderCreateEnumerationType( + DIB(cx), + self_metadata, + "Discriminant$".as_ptr().cast(), + "Discriminant$".len(), + unknown_file_metadata(cx), + UNKNOWN_LINE_NUMBER, + tag.value.size(cx).bits(), + tag.value.align(cx).abi.bits() as u32, + create_DIArray(DIB(cx), &tags), + type_metadata(cx, discr_enum_ty, self.span), + true, + ) + }; + + let variant_info = variant_info_for(dataful_variant); + let (variant_type_metadata, member_desc_factory) = describe_enum_variant( cx, - variant, - variant_info_for(dataful_variant), - OptimizedTag, - self.containing_scope, + dataful_variant_layout, + variant_info, + Some(NicheTag), + self_metadata, self.span, ); - let variant_member_descriptions = - member_description_factory.create_member_descriptions(cx); + let member_descriptions = member_desc_factory.create_member_descriptions(cx); set_members_of_composite_type( cx, self.enum_type, variant_type_metadata, - variant_member_descriptions, + member_descriptions, Some(&self.common_members), ); - // Encode the information about the null variant in the union - // member's name. - let mut name = String::from("RUST$ENCODED$ENUM$"); - // Right now it's not even going to work for `niche_start > 0`, - // and for multiple niche variants it only supports the first. - fn compute_field_path<'a, 'tcx>( - cx: &CodegenCx<'a, 'tcx>, - name: &mut String, - layout: TyAndLayout<'tcx>, - offset: Size, - size: Size, - ) { - for i in 0..layout.fields.count() { - let field_offset = layout.fields.offset(i); - if field_offset > offset { - continue; - } - let inner_offset = offset - field_offset; - let field = layout.field(cx, i); - if inner_offset + size <= field.size { - write!(name, "{}$", i).unwrap(); - compute_field_path(cx, name, field, inner_offset, size); - } - } - } - compute_field_path( - cx, - &mut name, - self.layout, - self.layout.fields.offset(tag_field), - self.layout.field(cx, tag_field).size, - ); - let variant_info = variant_info_for(*niche_variants.start()); - variant_info.map_struct_name(|variant_name| { - name.push_str(variant_name); - }); - - // Create the (singleton) list of descriptions of union members. - vec![MemberDescription { - name, - type_metadata: variant_type_metadata, - offset: Size::ZERO, - size: variant.size, - align: variant.align.abi, - flags: DIFlags::FlagZero, - discriminant: None, - source_info: variant_info.source_info(cx), - }] + let (size, align) = + cx.size_and_align_of(dataful_variant_layout.field(cx, tag_field).ty); + + vec![ + MemberDescription { + // Name the dataful variant so that we can identify it for natvis + name: "dataful_variant".to_string(), + type_metadata: variant_type_metadata, + offset: Size::ZERO, + size: self.layout.size, + align: self.layout.align.abi, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: variant_info.source_info(cx), + }, + MemberDescription { + name: "discriminant".into(), + type_metadata: discr_enum, + offset: dataful_variant_layout.fields.offset(tag_field), + size, + align, + flags: DIFlags::FlagZero, + discriminant: None, + source_info: None, + }, + ] } else { variants .iter_enumerated() @@ -1681,7 +1747,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { cx, variant, variant_info, - OptimizedTag, + Some(NicheTag), self_metadata, self.span, ); @@ -1697,19 +1763,7 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { Some(&self.common_members), ); - let niche_value = if i == dataful_variant { - None - } else { - let value = (i.as_u32() as u128) - .wrapping_sub(niche_variants.start().as_u32() as u128) - .wrapping_add(niche_start); - let value = tag.value.size(cx).truncate(value); - // NOTE(eddyb) do *NOT* remove this assert, until - // we pass the full 128-bit value to LLVM, otherwise - // truncation will be silent and remain undetected. - assert_eq!(value as u64 as u128, value); - Some(value as u64) - }; + let niche_value = calculate_niche_value(i); MemberDescription { name: variant_info.variant_name(), @@ -1771,14 +1825,10 @@ impl VariantMemberDescriptionFactory<'ll, 'tcx> { } } -// FIXME: terminology here should be aligned with `abi::TagEncoding`. -// `OptimizedTag` is `TagEncoding::Niche`, `RegularTag` is `TagEncoding::Direct`. -// `NoTag` should be removed; users should use `Option<EnumTagInfo>` instead. #[derive(Copy, Clone)] enum EnumTagInfo<'ll> { - RegularTag { tag_field: Field, tag_type_metadata: &'ll DIType }, - OptimizedTag, - NoTag, + DirectTag { tag_field: Field, tag_type_metadata: &'ll DIType }, + NicheTag, } #[derive(Copy, Clone)] @@ -1859,7 +1909,7 @@ fn describe_enum_variant( cx: &CodegenCx<'ll, 'tcx>, layout: layout::TyAndLayout<'tcx>, variant: VariantInfo<'_, 'tcx>, - discriminant_info: EnumTagInfo<'ll>, + discriminant_info: Option<EnumTagInfo<'ll>>, containing_scope: &'ll DIScope, span: Span, ) -> (&'ll DICompositeType, MemberDescriptionFactory<'ll, 'tcx>) { @@ -1882,12 +1932,11 @@ fn describe_enum_variant( let (offsets, args) = if use_enum_fallback(cx) { // If this is not a univariant enum, there is also the discriminant field. let (discr_offset, discr_arg) = match discriminant_info { - RegularTag { tag_field, .. } => { + Some(DirectTag { tag_field, .. }) => { // We have the layout of an enum variant, we need the layout of the outer enum let enum_layout = cx.layout_of(layout.ty); let offset = enum_layout.fields.offset(tag_field.as_usize()); - let args = - ("RUST$ENUM$DISR".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty); + let args = ("variant$".to_owned(), enum_layout.field(cx, tag_field.as_usize()).ty); (Some(offset), Some(args)) } _ => (None, None), @@ -1918,7 +1967,7 @@ fn describe_enum_variant( offsets, args, tag_type_metadata: match discriminant_info { - RegularTag { tag_type_metadata, .. } => Some(tag_type_metadata), + Some(DirectTag { tag_type_metadata, .. }) => Some(tag_type_metadata), _ => None, }, span, @@ -2048,9 +2097,9 @@ fn prepare_enum_metadata( if use_enum_fallback(cx) { let discriminant_type_metadata = match layout.variants { - Variants::Single { .. } - | Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, .. } => None, - Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => { + Variants::Single { .. } => None, + Variants::Multiple { tag_encoding: TagEncoding::Niche { .. }, ref tag, .. } + | Variants::Multiple { tag_encoding: TagEncoding::Direct, ref tag, .. } => { Some(discriminant_type_metadata(tag.value)) } }; @@ -2062,7 +2111,7 @@ fn prepare_enum_metadata( unsafe { llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), - containing_scope, + None, enum_name.as_ptr().cast(), enum_name.len(), file_metadata, @@ -2088,7 +2137,6 @@ fn prepare_enum_metadata( enum_type, layout, tag_type_metadata: discriminant_type_metadata, - containing_scope, common_members: vec![], span, }), @@ -2241,7 +2289,6 @@ fn prepare_enum_metadata( enum_type, layout, tag_type_metadata: None, - containing_scope, common_members: outer_fields, span, }), @@ -2437,7 +2484,7 @@ fn create_union_stub( llvm::LLVMRustDIBuilderCreateUnionType( DIB(cx), - containing_scope, + Some(containing_scope), union_type_name.as_ptr().cast(), union_type_name.len(), unknown_file_metadata(cx), diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 329458773ff..728f1224dd8 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -8,12 +8,11 @@ #![feature(bool_to_option)] #![feature(const_cstr_unchecked)] #![feature(crate_visibility_modifier)] -#![feature(extended_key_value_attributes)] +#![cfg_attr(bootstrap, feature(extended_key_value_attributes))] #![feature(extern_types)] #![feature(in_band_lifetimes)] #![feature(iter_zip)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![recursion_limit = "256"] use back::write::{create_informational_target_machine, create_target_machine}; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index bf66040a7eb..54ef1a28468 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -54,7 +54,7 @@ pub enum CallConv { } /// LLVMRustLinkage -#[derive(PartialEq)] +#[derive(Copy, Clone, PartialEq)] #[repr(C)] pub enum Linkage { ExternalLinkage = 0, @@ -72,6 +72,7 @@ pub enum Linkage { // LLVMRustVisibility #[repr(C)] +#[derive(Copy, Clone, PartialEq)] pub enum Visibility { Default = 0, Hidden = 1, @@ -1034,6 +1035,7 @@ extern "C" { pub fn LLVMDeleteGlobal(GlobalVar: &Value); pub fn LLVMGetInitializer(GlobalVar: &Value) -> Option<&Value>; pub fn LLVMSetInitializer(GlobalVar: &'a Value, ConstantVal: &'a Value); + pub fn LLVMIsThreadLocal(GlobalVar: &Value) -> Bool; pub fn LLVMSetThreadLocal(GlobalVar: &Value, IsThreadLocal: Bool); pub fn LLVMSetThreadLocalMode(GlobalVar: &Value, Mode: ThreadLocalMode); pub fn LLVMIsGlobalConstant(GlobalVar: &Value) -> Bool; @@ -2036,7 +2038,7 @@ extern "C" { pub fn LLVMRustDIBuilderCreateUnionType( Builder: &DIBuilder<'a>, - Scope: &'a DIScope, + Scope: Option<&'a DIScope>, Name: *const c_char, NameLen: size_t, File: &'a DIFile, diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 6101b90aea6..387062a671d 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -152,6 +152,12 @@ pub fn to_llvm_feature<'a>(sess: &Session, s: &'a str) -> &'a str { ("x86", "avx512vpclmulqdq") => "vpclmulqdq", ("aarch64", "fp") => "fp-armv8", ("aarch64", "fp16") => "fullfp16", + ("aarch64", "fhm") => "fp16fml", + ("aarch64", "rcpc2") => "rcpc-immo", + ("aarch64", "dpb") => "ccpp", + ("aarch64", "dpb2") => "ccdp", + ("aarch64", "frintts") => "fptoint", + ("aarch64", "fcma") => "complxnum", (_, s) => s, } } diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index fc1f364e9c6..93456443aa0 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -37,7 +37,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMRustSetLinkage(g, base::linkage_to_llvm(linkage)); llvm::LLVMRustSetVisibility(g, base::visibility_to_llvm(visibility)); - if self.should_assume_dso_local(linkage, visibility) { + if self.should_assume_dso_local(g, false) { llvm::LLVMRustSetDSOLocal(g, true); } } @@ -85,7 +85,7 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { attributes::from_fn_attrs(self, lldecl, instance); unsafe { - if self.should_assume_dso_local(linkage, visibility) { + if self.should_assume_dso_local(lldecl, false) { llvm::LLVMRustSetDSOLocal(lldecl, true); } } @@ -95,28 +95,48 @@ impl PreDefineMethods<'tcx> for CodegenCx<'ll, 'tcx> { } impl CodegenCx<'ll, 'tcx> { - /// Whether a definition (NB: not declaration!) can be assumed to be local to a group of + /// Whether a definition or declaration can be assumed to be local to a group of /// libraries that form a single DSO or executable. pub(crate) unsafe fn should_assume_dso_local( &self, - linkage: Linkage, - visibility: Visibility, + llval: &llvm::Value, + is_declaration: bool, ) -> bool { - if matches!(linkage, Linkage::Internal | Linkage::Private) { + let linkage = llvm::LLVMRustGetLinkage(llval); + let visibility = llvm::LLVMRustGetVisibility(llval); + + if matches!(linkage, llvm::Linkage::InternalLinkage | llvm::Linkage::PrivateLinkage) { return true; } - if visibility != Visibility::Default && linkage != Linkage::ExternalWeak { + if visibility != llvm::Visibility::Default && linkage != llvm::Linkage::ExternalWeakLinkage + { return true; } - // Static relocation model should force copy relocations everywhere. - if self.tcx.sess.relocation_model() == RelocModel::Static { + // Symbols from executables can't really be imported any further. + let all_exe = self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable); + let is_declaration_for_linker = + is_declaration || linkage == llvm::Linkage::AvailableExternallyLinkage; + if all_exe && !is_declaration_for_linker { return true; } - // Symbols from executables can't really be imported any further. - if self.tcx.sess.crate_types().iter().all(|ty| *ty == CrateType::Executable) { + // PowerPC64 prefers TOC indirection to avoid copy relocations. + if matches!(&*self.tcx.sess.target.arch, "powerpc64" | "powerpc64le") { + return false; + } + + // Thread-local variables generally don't support copy relocations. + let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval) + .map(|v| llvm::LLVMIsThreadLocal(v) == llvm::True) + .unwrap_or(false); + if is_thread_local_var { + return false; + } + + // Static relocation model should force copy relocations everywhere. + if self.tcx.sess.relocation_model() == RelocModel::Static { return true; } diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 68f40d5f863..3a677a2437c 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -9,7 +9,7 @@ test = false [dependencies] bitflags = "1.2.1" -cc = "1.0.67" +cc = "1.0.68" itertools = "0.9" tracing = "0.1" libc = "0.2.50" @@ -24,7 +24,7 @@ rustc_middle = { path = "../rustc_middle" } rustc_apfloat = { path = "../rustc_apfloat" } rustc_attr = { path = "../rustc_attr" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } -rustc_data_structures = { path = "../rustc_data_structures"} +rustc_data_structures = { path = "../rustc_data_structures" } rustc_errors = { path = "../rustc_errors" } rustc_fs_util = { path = "../rustc_fs_util" } rustc_hir = { path = "../rustc_hir" } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e330b5e703b..32275e9b073 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1805,13 +1805,14 @@ fn add_local_native_libraries( let search_path = archive_search_paths(sess); let mut last = (NativeLibKind::Unspecified, None); for lib in relevant_libs { - // Skip if this library is the same as the last. - last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) }; - let name = match lib.name { Some(l) => l, None => continue, }; + + // Skip if this library is the same as the last. + last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) }; + let verbatim = lib.verbatim.unwrap_or(false); match lib.kind { NativeLibKind::Dylib { as_needed } => { @@ -2144,9 +2145,6 @@ fn add_upstream_native_libraries( let mut last = (NativeLibKind::Unspecified, None); for &(cnum, _) in crates { for lib in codegen_results.crate_info.native_libraries[&cnum].iter() { - // Skip if this library is the same as the last. - last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) }; - let name = match lib.name { Some(l) => l, None => continue, @@ -2154,6 +2152,10 @@ fn add_upstream_native_libraries( if !relevant_lib(sess, &lib) { continue; } + + // Skip if this library is the same as the last. + last = if (lib.kind, lib.name) == last { continue } else { (lib.kind, lib.name) }; + let verbatim = lib.verbatim.unwrap_or(false); match lib.kind { NativeLibKind::Dylib { as_needed } => { diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs index ea4564c2a6b..4dc9a3f5e41 100644 --- a/compiler/rustc_codegen_ssa/src/back/linker.rs +++ b/compiler/rustc_codegen_ssa/src/back/linker.rs @@ -281,8 +281,11 @@ impl<'a> Linker for GccLinker<'a> { } } LinkOutputKind::DynamicPicExe => { - // `-pie` works for both gcc wrapper and ld. - self.cmd.arg("-pie"); + // noop on windows w/ gcc & ld, error w/ lld + if !self.sess.target.is_like_windows { + // `-pie` works for both gcc wrapper and ld. + self.cmd.arg("-pie"); + } } LinkOutputKind::StaticNoPicExe => { // `-static` works for both gcc wrapper and ld. @@ -347,7 +350,7 @@ impl<'a> Linker for GccLinker<'a> { // has -needed-l{} / -needed_library {} // but we have no way to detect that here. self.sess.warn("`as-needed` modifier not implemented yet for ld64"); - } else if self.sess.target.linker_is_gnu { + } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows { self.linker_arg("--no-as-needed"); } else { self.sess.warn("`as-needed` modifier not supported for current linker"); @@ -358,7 +361,7 @@ impl<'a> Linker for GccLinker<'a> { if !as_needed { if self.sess.target.is_like_osx { // See above FIXME comment - } else if self.sess.target.linker_is_gnu { + } else if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows { self.linker_arg("--as-needed"); } } @@ -469,7 +472,7 @@ impl<'a> Linker for GccLinker<'a> { // eliminate the metadata. If we're building an executable, however, // --gc-sections drops the size of hello world from 1.8MB to 597K, a 67% // reduction. - } else if !keep_metadata { + } else if self.sess.target.linker_is_gnu && !keep_metadata { self.linker_arg("--gc-sections"); } } @@ -477,9 +480,7 @@ impl<'a> Linker for GccLinker<'a> { fn no_gc_sections(&mut self) { if self.sess.target.is_like_osx { self.linker_arg("-no_dead_strip"); - } else if self.sess.target.is_like_solaris { - self.linker_arg("-zrecord"); - } else { + } else if self.sess.target.linker_is_gnu { self.linker_arg("--no-gc-sections"); } } @@ -692,7 +693,7 @@ impl<'a> Linker for GccLinker<'a> { } fn add_as_needed(&mut self) { - if self.sess.target.linker_is_gnu { + if self.sess.target.linker_is_gnu && !self.sess.target.is_like_windows { self.linker_arg("--as-needed"); } else if self.sess.target.is_like_solaris { // -z ignore is the Solaris equivalent to the GNU ld --as-needed option diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs index 08442c588f8..c1dfe1ef856 100644 --- a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs +++ b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs @@ -28,6 +28,7 @@ pub struct Expression { /// only whitespace or comments). According to LLVM Code Coverage Mapping documentation, "A count /// for a gap area is only used as the line execution count if there are no other regions on a /// line." +#[derive(Debug)] pub struct FunctionCoverage<'tcx> { instance: Instance<'tcx>, source_hash: u64, @@ -113,6 +114,14 @@ impl<'tcx> FunctionCoverage<'tcx> { expression_id, lhs, op, rhs, region ); let expression_index = self.expression_index(u32::from(expression_id)); + debug_assert!( + expression_index.as_usize() < self.expressions.len(), + "expression_index {} is out of range for expressions.len() = {} + for {:?}", + expression_index.as_usize(), + self.expressions.len(), + self, + ); if let Some(previous_expression) = self.expressions[expression_index].replace(Expression { lhs, op, diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index d1bbf74307c..7b4b0821c4b 100644 --- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -3,7 +3,8 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt}; +use rustc_middle::ty::{self, subst::SubstsRef, AdtDef, Ty, TyCtxt}; +use rustc_target::abi::{TagEncoding, Variants}; use std::fmt::Write; @@ -45,8 +46,12 @@ pub fn push_debuginfo_type_name<'tcx>( ty::Float(float_ty) => output.push_str(float_ty.name_str()), ty::Foreign(def_id) => push_item_name(tcx, def_id, qualified, output), ty::Adt(def, substs) => { - push_item_name(tcx, def.did, qualified, output); - push_type_params(tcx, substs, output, visited); + if def.is_enum() && cpp_like_names { + msvc_enum_fallback(tcx, t, def, substs, output, visited); + } else { + push_item_name(tcx, def.did, qualified, output); + push_type_params(tcx, substs, output, visited); + } } ty::Tuple(component_types) => { if cpp_like_names { @@ -233,6 +238,54 @@ pub fn push_debuginfo_type_name<'tcx>( } } + /// MSVC names enums differently than other platforms so that the debugging visualization + // format (natvis) is able to understand enums and render the active variant correctly in the + // debugger. For more information, look in `src/etc/natvis/intrinsic.natvis` and + // `EnumMemberDescriptionFactor::create_member_descriptions`. + fn msvc_enum_fallback( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + def: &AdtDef, + substs: SubstsRef<'tcx>, + output: &mut String, + visited: &mut FxHashSet<Ty<'tcx>>, + ) { + let layout = tcx.layout_of(tcx.param_env(def.did).and(ty)).expect("layout error"); + + if let Variants::Multiple { + tag_encoding: TagEncoding::Niche { dataful_variant, .. }, + tag, + variants, + .. + } = &layout.variants + { + let dataful_variant_layout = &variants[*dataful_variant]; + + // calculate the range of values for the dataful variant + let dataful_discriminant_range = + &dataful_variant_layout.largest_niche.as_ref().unwrap().scalar.valid_range; + + let min = dataful_discriminant_range.start(); + let min = tag.value.size(&tcx).truncate(*min); + + let max = dataful_discriminant_range.end(); + let max = tag.value.size(&tcx).truncate(*max); + + output.push_str("enum$<"); + push_item_name(tcx, def.did, true, output); + push_type_params(tcx, substs, output, visited); + + let dataful_variant_name = def.variants[*dataful_variant].ident.as_str(); + + output.push_str(&format!(", {}, {}, {}>", min, max, dataful_variant_name)); + } else { + output.push_str("enum$<"); + push_item_name(tcx, def.did, true, output); + push_type_params(tcx, substs, output, visited); + output.push('>'); + } + } + fn push_item_name(tcx: TyCtxt<'tcx>, def_id: DefId, qualified: bool, output: &mut String) { if qualified { output.push_str(&tcx.crate_name(def_id.krate).as_str()); diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 1b53b551901..12da3d9e155 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,16 +1,11 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(assert_matches)] #![feature(bool_to_option)] #![feature(box_patterns)] -#![feature(drain_filter)] #![feature(try_blocks)] #![feature(in_band_lifetimes)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(associated_type_bounds)] -#![feature(iter_zip)] #![recursion_limit = "256"] -#![feature(box_syntax)] //! This crate contains codegen code that is used by all codegen backends (LLVM and others). //! The backend-agnostic functions of this crate use functions defined in various traits that diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 4e987908b4e..98d550d732f 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -17,6 +17,8 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("neon", Some(sym::arm_target_feature)), ("crc", Some(sym::arm_target_feature)), ("crypto", Some(sym::arm_target_feature)), + ("aes", Some(sym::arm_target_feature)), + ("sha2", Some(sym::arm_target_feature)), ("v5te", Some(sym::arm_target_feature)), ("v6", Some(sym::arm_target_feature)), ("v6k", Some(sym::arm_target_feature)), @@ -33,22 +35,95 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("thumb-mode", Some(sym::arm_target_feature)), ]; +// Commented features are not available in LLVM 10.0, or have since been renamed const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ - ("fp", Some(sym::aarch64_target_feature)), + // FEAT_AdvSimd ("neon", Some(sym::aarch64_target_feature)), + // FEAT_FP + ("fp", Some(sym::aarch64_target_feature)), + // FEAT_FP16 + ("fp16", Some(sym::aarch64_target_feature)), + // FEAT_SVE ("sve", Some(sym::aarch64_target_feature)), + // FEAT_CRC ("crc", Some(sym::aarch64_target_feature)), + // Cryptographic extension ("crypto", Some(sym::aarch64_target_feature)), + // FEAT_RAS ("ras", Some(sym::aarch64_target_feature)), + // FEAT_LSE ("lse", Some(sym::aarch64_target_feature)), + // FEAT_RDM ("rdm", Some(sym::aarch64_target_feature)), - ("fp16", Some(sym::aarch64_target_feature)), + // FEAT_RCPC ("rcpc", Some(sym::aarch64_target_feature)), + // FEAT_RCPC2 + ("rcpc2", Some(sym::aarch64_target_feature)), + // FEAT_DotProd ("dotprod", Some(sym::aarch64_target_feature)), + // FEAT_TME ("tme", Some(sym::aarch64_target_feature)), + // FEAT_FHM + ("fhm", Some(sym::aarch64_target_feature)), + // FEAT_DIT + ("dit", Some(sym::aarch64_target_feature)), + // FEAT_FLAGM + // ("flagm", Some(sym::aarch64_target_feature)), + // FEAT_SSBS + ("ssbs", Some(sym::aarch64_target_feature)), + // FEAT_SB + ("sb", Some(sym::aarch64_target_feature)), + // FEAT_PAUTH + // ("pauth", Some(sym::aarch64_target_feature)), + // FEAT_DPB + ("dpb", Some(sym::aarch64_target_feature)), + // FEAT_DPB2 + ("dpb2", Some(sym::aarch64_target_feature)), + // FEAT_SVE2 + ("sve2", Some(sym::aarch64_target_feature)), + // FEAT_SVE2_AES + ("sve2-aes", Some(sym::aarch64_target_feature)), + // FEAT_SVE2_SM4 + ("sve2-sm4", Some(sym::aarch64_target_feature)), + // FEAT_SVE2_SHA3 + ("sve2-sha3", Some(sym::aarch64_target_feature)), + // FEAT_SVE2_BitPerm + ("sve2-bitperm", Some(sym::aarch64_target_feature)), + // FEAT_FRINTTS + ("frintts", Some(sym::aarch64_target_feature)), + // FEAT_I8MM + // ("i8mm", Some(sym::aarch64_target_feature)), + // FEAT_F32MM + // ("f32mm", Some(sym::aarch64_target_feature)), + // FEAT_F64MM + // ("f64mm", Some(sym::aarch64_target_feature)), + // FEAT_BF16 + // ("bf16", Some(sym::aarch64_target_feature)), + // FEAT_RAND + ("rand", Some(sym::aarch64_target_feature)), + // FEAT_BTI + ("bti", Some(sym::aarch64_target_feature)), + // FEAT_MTE + ("mte", Some(sym::aarch64_target_feature)), + // FEAT_JSCVT + ("jsconv", Some(sym::aarch64_target_feature)), + // FEAT_FCMA + ("fcma", Some(sym::aarch64_target_feature)), + // FEAT_AES + ("aes", Some(sym::aarch64_target_feature)), + // FEAT_SHA1 & FEAT_SHA256 + ("sha2", Some(sym::aarch64_target_feature)), + // FEAT_SHA512 & FEAT_SHA3 + ("sha3", Some(sym::aarch64_target_feature)), + // FEAT_SM3 & FEAT_SM4 + ("sm4", Some(sym::aarch64_target_feature)), ("v8.1a", Some(sym::aarch64_target_feature)), ("v8.2a", Some(sym::aarch64_target_feature)), ("v8.3a", Some(sym::aarch64_target_feature)), + ("v8.4a", Some(sym::aarch64_target_feature)), + ("v8.5a", Some(sym::aarch64_target_feature)), + // ("v8.6a", Some(sym::aarch64_target_feature)), + // ("v8.7a", Some(sym::aarch64_target_feature)), ]; const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index aa95ecbdaf9..c35a164bb33 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -34,7 +34,7 @@ tempfile = "3.2" version = "0.11" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["fileapi", "psapi"] } +winapi = { version = "0.3", features = ["fileapi", "psapi", "winerror"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] memmap2 = "0.2.1" diff --git a/compiler/rustc_data_structures/src/flock.rs b/compiler/rustc_data_structures/src/flock.rs index 9383be474fd..4f5d8d7ea48 100644 --- a/compiler/rustc_data_structures/src/flock.rs +++ b/compiler/rustc_data_structures/src/flock.rs @@ -54,6 +54,10 @@ cfg_if! { Ok(Lock { _file: file }) } } + + pub fn error_unsupported(err: &io::Error) -> bool { + matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS)) + } } // Note that we don't need a Drop impl to execute `flock(fd, LOCK_UN)`. Lock acquired by @@ -103,6 +107,10 @@ cfg_if! { Ok(Lock { file }) } } + + pub fn error_unsupported(err: &io::Error) -> bool { + matches!(err.raw_os_error(), Some(libc::ENOTSUP) | Some(libc::ENOSYS)) + } } impl Drop for Lock { @@ -122,6 +130,7 @@ cfg_if! { use std::mem; use std::os::windows::prelude::*; + use winapi::shared::winerror::ERROR_INVALID_FUNCTION; use winapi::um::minwinbase::{OVERLAPPED, LOCKFILE_FAIL_IMMEDIATELY, LOCKFILE_EXCLUSIVE_LOCK}; use winapi::um::fileapi::LockFileEx; use winapi::um::winnt::{FILE_SHARE_DELETE, FILE_SHARE_READ, FILE_SHARE_WRITE}; @@ -194,6 +203,10 @@ cfg_if! { Ok(Lock { _file: file }) } } + + pub fn error_unsupported(err: &io::Error) -> bool { + err.raw_os_error() == Some(ERROR_INVALID_FUNCTION as i32) + } } // Note that we don't need a Drop impl on the Windows: The file is unlocked diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index adbb98fa750..a8b9f479f1e 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -10,15 +10,12 @@ #![feature(array_windows)] #![feature(control_flow_enum)] #![feature(in_band_lifetimes)] -#![feature(unboxed_closures)] #![feature(generator_trait)] -#![feature(fn_traits)] #![feature(min_specialization)] #![feature(auto_traits)] #![feature(nll)] #![feature(allow_internal_unstable)] #![feature(hash_raw_entry)] -#![feature(stmt_expr_attributes)] #![feature(core_intrinsics)] #![feature(test)] #![feature(associated_type_bounds)] diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs index 29d685ab530..3aabe94bfc6 100644 --- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs +++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs @@ -597,7 +597,7 @@ impl<O: ForestObligation> ObligationForest<O> { Some(rpos) => { // Cycle detected. processor.process_backedge( - stack[rpos..].iter().map(GetObligation(&self.nodes)), + stack[rpos..].iter().map(|&i| &self.nodes[i].obligation), PhantomData, ); } @@ -705,20 +705,3 @@ impl<O: ForestObligation> ObligationForest<O> { }); } } - -// I need a Clone closure. -#[derive(Clone)] -struct GetObligation<'a, O>(&'a [Node<O>]); - -impl<'a, 'b, O> FnOnce<(&'b usize,)> for GetObligation<'a, O> { - type Output = &'a O; - extern "rust-call" fn call_once(self, args: (&'b usize,)) -> &'a O { - &self.0[*args.0].obligation - } -} - -impl<'a, 'b, O> FnMut<(&'b usize,)> for GetObligation<'a, O> { - extern "rust-call" fn call_mut(&mut self, args: (&'b usize,)) -> &'a O { - &self.0[*args.0].obligation - } -} diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs index ff28784a1dc..18b352cf3b0 100644 --- a/compiler/rustc_data_structures/src/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -550,35 +550,3 @@ pub fn hash_stable_hashmap<HCX, K, V, R, SK, F>( entries.sort_unstable_by(|&(ref sk1, _), &(ref sk2, _)| sk1.cmp(sk2)); entries.hash_stable(hcx, hasher); } - -/// A vector container that makes sure that its items are hashed in a stable -/// order. -#[derive(Debug)] -pub struct StableVec<T>(Vec<T>); - -impl<T> StableVec<T> { - pub fn new(v: Vec<T>) -> Self { - StableVec(v) - } -} - -impl<T> ::std::ops::Deref for StableVec<T> { - type Target = Vec<T>; - - fn deref(&self) -> &Vec<T> { - &self.0 - } -} - -impl<T, HCX> HashStable<HCX> for StableVec<T> -where - T: HashStable<HCX> + ToStableHashKey<HCX>, -{ - fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) { - let StableVec(ref v) = *self; - - let mut sorted: Vec<_> = v.iter().map(|x| x.to_stable_hash_key(hcx)).collect(); - sorted.sort_unstable(); - sorted.hash_stable(hcx, hasher); - } -} diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 26706cd2b1b..722ce6b6367 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -43,49 +43,9 @@ cfg_if! { use std::ops::Add; use std::panic::{resume_unwind, catch_unwind, AssertUnwindSafe}; - /// This is a single threaded variant of AtomicCell provided by crossbeam. - /// Unlike `Atomic` this is intended for all `Copy` types, - /// but it lacks the explicit ordering arguments. - #[derive(Debug)] - pub struct AtomicCell<T: Copy>(Cell<T>); - - impl<T: Copy> AtomicCell<T> { - #[inline] - pub fn new(v: T) -> Self { - AtomicCell(Cell::new(v)) - } - - #[inline] - pub fn get_mut(&mut self) -> &mut T { - self.0.get_mut() - } - } - - impl<T: Copy> AtomicCell<T> { - #[inline] - pub fn into_inner(self) -> T { - self.0.into_inner() - } - - #[inline] - pub fn load(&self) -> T { - self.0.get() - } - - #[inline] - pub fn store(&self, val: T) { - self.0.set(val) - } - - #[inline] - pub fn swap(&self, val: T) -> T { - self.0.replace(val) - } - } - /// This is a single threaded variant of `AtomicU64`, `AtomicUsize`, etc. - /// It differs from `AtomicCell` in that it has explicit ordering arguments - /// and is only intended for use with the native atomic types. + /// It has explicit ordering arguments and is only intended for use with + /// the native atomic types. /// You should use this type through the `AtomicU64`, `AtomicUsize`, etc, type aliases /// as it's not intended to be used separately. #[derive(Debug)] @@ -159,22 +119,6 @@ cfg_if! { (oper_a(), oper_b()) } - pub struct SerialScope; - - impl SerialScope { - pub fn spawn<F>(&self, f: F) - where F: FnOnce(&SerialScope) - { - f(self) - } - } - - pub fn scope<F, R>(f: F) -> R - where F: FnOnce(&SerialScope) -> R - { - f(&SerialScope) - } - #[macro_export] macro_rules! parallel { ($($blocks:tt),*) => { @@ -318,8 +262,6 @@ cfg_if! { pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64}; - pub use crossbeam_utils::atomic::AtomicCell; - pub use std::sync::Arc as Lrc; pub use std::sync::Weak as Weak; diff --git a/compiler/rustc_data_structures/src/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs index cd1e12ca450..324a8624dd0 100644 --- a/compiler/rustc_data_structures/src/tagged_ptr.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr.rs @@ -90,9 +90,11 @@ pub unsafe trait Tag: Copy { unsafe impl<T> Pointer for Box<T> { const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; + #[inline] fn into_usize(self) -> usize { Box::into_raw(self) as usize } + #[inline] unsafe fn from_usize(ptr: usize) -> Self { Box::from_raw(ptr as *mut T) } @@ -104,9 +106,11 @@ unsafe impl<T> Pointer for Box<T> { unsafe impl<T> Pointer for Rc<T> { const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; + #[inline] fn into_usize(self) -> usize { Rc::into_raw(self) as usize } + #[inline] unsafe fn from_usize(ptr: usize) -> Self { Rc::from_raw(ptr as *const T) } @@ -118,9 +122,11 @@ unsafe impl<T> Pointer for Rc<T> { unsafe impl<T> Pointer for Arc<T> { const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; + #[inline] fn into_usize(self) -> usize { Arc::into_raw(self) as usize } + #[inline] unsafe fn from_usize(ptr: usize) -> Self { Arc::from_raw(ptr as *const T) } @@ -132,9 +138,11 @@ unsafe impl<T> Pointer for Arc<T> { unsafe impl<'a, T: 'a> Pointer for &'a T { const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; + #[inline] fn into_usize(self) -> usize { self as *const T as usize } + #[inline] unsafe fn from_usize(ptr: usize) -> Self { &*(ptr as *const T) } @@ -145,9 +153,11 @@ unsafe impl<'a, T: 'a> Pointer for &'a T { unsafe impl<'a, T: 'a> Pointer for &'a mut T { const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize; + #[inline] fn into_usize(self) -> usize { self as *mut T as usize } + #[inline] unsafe fn from_usize(ptr: usize) -> Self { &mut *(ptr as *mut T) } diff --git a/compiler/rustc_driver/src/pretty.rs b/compiler/rustc_driver/src/pretty.rs index 370ec053cbb..a2b4f3fcf73 100644 --- a/compiler/rustc_driver/src/pretty.rs +++ b/compiler/rustc_driver/src/pretty.rs @@ -8,14 +8,12 @@ use rustc_hir_pretty as pprust_hir; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::{self, TyCtxt}; use rustc_mir::util::{write_mir_graphviz, write_mir_pretty}; -use rustc_mir_build::thir; use rustc_session::config::{Input, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::FileName; use std::cell::Cell; -use std::fmt::Write; use std::path::Path; pub use self::PpMode::*; @@ -490,18 +488,8 @@ fn print_with_analysis( } ThirTree => { - let mut out = String::new(); - abort_on_err(rustc_typeck::check_crate(tcx), tcx.sess); - debug!("pretty printing THIR tree"); - for did in tcx.body_owners() { - let hir = tcx.hir(); - let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(did))); - let arena = thir::Arena::default(); - let thir = - thir::build_thir(tcx, ty::WithOptConstParam::unknown(did), &arena, &body.value); - let _ = writeln!(out, "{:?}:\n{:#?}\n", did, thir); - } - out + // FIXME(rust-lang/project-thir-unsafeck#8) + todo!() } _ => unreachable!(), diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index f53ce7ceace..979f2d3b300 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -5,7 +5,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(crate_visibility_modifier)] #![feature(backtrace)] -#![feature(extended_key_value_attributes)] +#![cfg_attr(bootstrap, feature(extended_key_value_attributes))] #![feature(format_args_capture)] #![feature(iter_zip)] #![feature(nll)] @@ -715,6 +715,7 @@ impl Handler { self.inner.borrow_mut().bug(msg) } + #[inline] pub fn err_count(&self) -> usize { self.inner.borrow().err_count() } @@ -924,6 +925,7 @@ impl HandlerInner { } } + #[inline] fn err_count(&self) -> usize { self.err_count + self.stashed_diagnostics.len() } diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index 5fb85867501..f77eac2b068 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,9 +1,7 @@ -#![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(destructuring_assignment)] #![feature(iter_zip)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(proc_macro_diagnostic)] #![feature(proc_macro_internals)] #![feature(proc_macro_span)] diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index 91d4a0f0d65..6608573d720 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -467,6 +467,7 @@ pub fn compile_declarative_macro( &sess.parse_sess, def.id, features, + edition, ) .pop() .unwrap(); @@ -492,6 +493,7 @@ pub fn compile_declarative_macro( &sess.parse_sess, def.id, features, + edition, ) .pop() .unwrap(); diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index aca02ef93f8..fb7479eafc8 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -9,7 +9,8 @@ use rustc_feature::Features; use rustc_session::parse::ParseSess; use rustc_span::symbol::{kw, Ident}; -use rustc_span::Span; +use rustc_span::edition::Edition; +use rustc_span::{Span, SyntaxContext}; use rustc_data_structures::sync::Lrc; @@ -32,6 +33,7 @@ const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \ /// - `sess`: the parsing session. Any errors will be emitted to this session. /// - `node_id`: the NodeId of the macro we are parsing. /// - `features`: language features so we can do feature gating. +/// - `edition`: the edition of the crate defining the macro /// /// # Returns /// @@ -42,6 +44,7 @@ pub(super) fn parse( sess: &ParseSess, node_id: NodeId, features: &Features, + edition: Edition, ) -> Vec<TokenTree> { // Will contain the final collection of `self::TokenTree` let mut result = Vec::new(); @@ -52,7 +55,7 @@ pub(super) fn parse( while let Some(tree) = trees.next() { // Given the parsed tree, if there is a metavar and we are expecting matchers, actually // parse out the matcher (i.e., in `$id:ident` this would parse the `:` and `ident`). - let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features); + let tree = parse_tree(tree, &mut trees, expect_matchers, sess, node_id, features, edition); match tree { TokenTree::MetaVar(start_sp, ident) if expect_matchers => { let span = match trees.next() { @@ -64,7 +67,19 @@ pub(super) fn parse( let kind = token::NonterminalKind::from_symbol(frag.name, || { - span.edition() + // FIXME(#85708) - once we properly decode a foreign + // crate's `SyntaxContext::root`, then we can replace + // this with just `span.edition()`. A + // `SyntaxContext::root()` from the current crate will + // have the edition of the current crate, and a + // `SyntaxxContext::root()` from a foreign crate will + // have the edition of that crate (which we manually + // retrieve via the `edition` parameter). + if span.ctxt() == SyntaxContext::root() { + edition + } else { + span.edition() + } }) .unwrap_or_else( || { @@ -117,6 +132,7 @@ pub(super) fn parse( /// - `expect_matchers`: same as for `parse` (see above). /// - `sess`: the parsing session. Any errors will be emitted to this session. /// - `features`: language features so we can do feature gating. +/// - `edition` - the edition of the crate defining the macro fn parse_tree( tree: tokenstream::TokenTree, outer_trees: &mut impl Iterator<Item = tokenstream::TokenTree>, @@ -124,6 +140,7 @@ fn parse_tree( sess: &ParseSess, node_id: NodeId, features: &Features, + edition: Edition, ) -> TokenTree { // Depending on what `tree` is, we could be parsing different parts of a macro match tree { @@ -151,7 +168,7 @@ fn parse_tree( sess.span_diagnostic.span_err(span.entire(), &msg); } // Parse the contents of the sequence itself - let sequence = parse(tts, expect_matchers, sess, node_id, features); + let sequence = parse(tts, expect_matchers, sess, node_id, features, edition); // Get the Kleene operator and optional separator let (separator, kleene) = parse_sep_and_kleene_op(&mut trees, span.entire(), sess); @@ -204,7 +221,7 @@ fn parse_tree( span, Lrc::new(Delimited { delim, - tts: parse(tts, expect_matchers, sess, node_id, features), + tts: parse(tts, expect_matchers, sess, node_id, features, edition), }), ), } diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs index 7bf6502c976..92315c4d4f6 100644 --- a/compiler/rustc_expand/src/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -1,9 +1,7 @@ use crate::base::{ExtCtxt, ResolverExpand}; use rustc_ast as ast; -use rustc_ast::token; -use rustc_ast::token::Nonterminal; -use rustc_ast::token::NtIdent; +use rustc_ast::token::{self, Nonterminal, NtIdent, TokenKind}; use rustc_ast::tokenstream::{self, CanSynthesizeMissingTokens}; use rustc_ast::tokenstream::{DelimSpan, Spacing::*, TokenStream, TreeAndSpacing}; use rustc_ast_pretty::pprust; @@ -541,6 +539,33 @@ impl server::Ident for Rustc<'_> { } impl server::Literal for Rustc<'_> { + fn from_str(&mut self, s: &str) -> Result<Self::Literal, ()> { + let override_span = None; + let stream = parse_stream_from_source_str( + FileName::proc_macro_source_code(s), + s.to_owned(), + self.sess, + override_span, + ); + if stream.len() != 1 { + return Err(()); + } + let tree = stream.into_trees().next().unwrap(); + let token = match tree { + tokenstream::TokenTree::Token(token) => token, + tokenstream::TokenTree::Delimited { .. } => return Err(()), + }; + let span_data = token.span.data(); + if (span_data.hi.0 - span_data.lo.0) as usize != s.len() { + // There is a comment or whitespace adjacent to the literal. + return Err(()); + } + let lit = match token.kind { + TokenKind::Literal(lit) => lit, + _ => return Err(()), + }; + Ok(Literal { lit, span: self.call_site }) + } fn debug_kind(&mut self, literal: &Self::Literal) -> String { format!("{:?}", literal.lit.kind) } diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs index e8642a52749..95504723e7b 100644 --- a/compiler/rustc_feature/src/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -281,6 +281,12 @@ declare_features! ( (accepted, or_patterns, "1.53.0", Some(54883), None), /// Allows defining identifiers beyond ASCII. (accepted, non_ascii_idents, "1.53.0", Some(55467), None), + /// Allows arbitrary expressions in key-value attributes at parse time. + (accepted, extended_key_value_attributes, "1.54.0", Some(78835), None), + /// Allows unsizing coercions in `const fn`. + (accepted, const_fn_unsize, "1.54.0", Some(64992), None), + /// Allows `impl Trait` with multiple unrelated lifetimes. + (accepted, member_constraints, "1.54.0", Some(61997), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 80fe5bafc6e..a84737e80a0 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -472,9 +472,6 @@ declare_features! ( /// Allows explicit discriminants on non-unit enum variants. (active, arbitrary_enum_discriminant, "1.37.0", Some(60553), None), - /// Allows `impl Trait` with multiple unrelated lifetimes. - (active, member_constraints, "1.37.0", Some(61997), None), - /// Allows `async || body` closures. (active, async_closure, "1.37.0", Some(62290), None), @@ -601,9 +598,6 @@ declare_features! ( /// Allows capturing disjoint fields in a closure/generator (RFC 2229). (active, capture_disjoint_fields, "1.49.0", Some(53488), None), - /// Allows arbitrary expressions in key-value attributes at parse time. - (active, extended_key_value_attributes, "1.50.0", Some(78835), None), - /// Allows const generics to have default values (e.g. `struct Foo<const N: usize = 3>(...);`). (active, const_generics_defaults, "1.51.0", Some(44580), None), @@ -647,9 +641,6 @@ declare_features! ( /// Allows trait bounds in `const fn`. (active, const_fn_trait_bound, "1.53.0", Some(57563), None), - /// Allows unsizing coercions in `const fn`. - (active, const_fn_unsize, "1.53.0", Some(64992), None), - /// Allows `async {}` expressions in const contexts. (active, const_async_blocks, "1.53.0", Some(85368), None), @@ -698,14 +689,8 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::repr128, sym::unsized_locals, sym::capture_disjoint_fields, - sym::const_generics_defaults, sym::inherent_associated_types, sym::type_alias_impl_trait, - sym::native_link_modifiers, - sym::native_link_modifiers_bundle, - sym::native_link_modifiers_verbatim, - sym::native_link_modifiers_whole_archive, - sym::native_link_modifiers_as_needed, sym::rustc_insignificant_dtor, sym::unnamed_fields, ]; diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index e7e128f8a9b..259a6328a22 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -569,10 +569,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_attr!(TEST, rustc_if_this_changed, AssumedUsed, template!(Word, List: "DepNode")), rustc_attr!(TEST, rustc_then_this_would_need, AssumedUsed, template!(List: "DepNode")), rustc_attr!( - TEST, rustc_dirty, AssumedUsed, - template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), - ), - rustc_attr!( TEST, rustc_clean, AssumedUsed, template!(List: r#"cfg = "...", /*opt*/ label = "...", /*opt*/ except = "...""#), ), diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs index 647d735fb86..fda1ba80952 100644 --- a/compiler/rustc_hir/src/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -14,7 +14,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::unhash::UnhashMap; use rustc_index::vec::IndexVec; -use rustc_span::crate_disambiguator::CrateDisambiguator; use rustc_span::hygiene::ExpnId; use rustc_span::symbol::{kw, sym, Symbol}; @@ -306,6 +305,7 @@ impl Definitions { self.table.index_to_key.len() } + #[inline] pub fn def_key(&self, id: LocalDefId) -> DefKey { self.table.def_key(id.local_def_index) } @@ -338,7 +338,7 @@ impl Definitions { } /// Adds a root definition (no parent) and a few other reserved definitions. - pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> Definitions { + pub fn new(stable_crate_id: StableCrateId) -> Definitions { let key = DefKey { parent: None, disambiguated_data: DisambiguatedDefPathData { @@ -347,7 +347,6 @@ impl Definitions { }, }; - let stable_crate_id = StableCrateId::new(crate_name, crate_disambiguator); let parent_hash = DefPathHash::new(stable_crate_id, 0); let def_path_hash = key.compute_stable_hash(parent_hash); diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 91fd97a0d40..577d43b1c8e 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,7 +1,7 @@ // ignore-tidy-filelength use crate::def::{CtorKind, DefKind, Res}; use crate::def_id::DefId; -crate use crate::hir_id::HirId; +crate use crate::hir_id::{HirId, ItemLocalId}; use crate::{itemlikevisit, LangItem}; use rustc_ast::util::parser::ExprPrecedence; @@ -10,6 +10,7 @@ use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, TraitObject pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto}; pub use rustc_ast::{CaptureBy, Movability, Mutability}; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; use rustc_macros::HashStable_Generic; use rustc_span::source_map::Spanned; @@ -658,7 +659,9 @@ pub struct Crate<'hir> { /// they are declared in the static array generated by proc_macro_harness. pub proc_macros: Vec<HirId>, - pub trait_map: BTreeMap<HirId, Vec<TraitCandidate>>, + /// Map indicating what traits are in scope for places where this + /// is relevant; generated by resolve. + pub trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, Box<[TraitCandidate]>>>, /// Collected attributes from HIR nodes. pub attrs: BTreeMap<HirId, &'hir [Attribute]>, @@ -2485,6 +2488,7 @@ pub enum FnRetTy<'hir> { } impl FnRetTy<'_> { + #[inline] pub fn span(&self) -> Span { match *self { Self::DefaultReturn(span) => span, diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 7b788b13b9f..0b8535f8ca5 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -308,12 +308,12 @@ language_item_table! { Termination, sym::termination, termination, Target::Trait; - Try, kw::Try, try_trait, Target::Trait; + Try, sym::Try, try_trait, Target::Trait; // Language items from AST lowering - TryFromError, sym::from_error, from_error_fn, Target::Method(MethodKind::Trait { body: false }); - TryFromOk, sym::from_ok, from_ok_fn, Target::Method(MethodKind::Trait { body: false }); - TryIntoResult, sym::into_result, into_result_fn, Target::Method(MethodKind::Trait { body: false }); + TryTraitFromResidual, sym::from_residual, from_residual_fn, Target::Method(MethodKind::Trait { body: false }); + TryTraitFromOutput, sym::from_output, from_output_fn, Target::Method(MethodKind::Trait { body: false }); + TryTraitBranch, sym::branch, branch_fn, Target::Method(MethodKind::Trait { body: false }); PollReady, sym::Ready, poll_ready_variant, Target::Variant; PollPending, sym::Pending, poll_pending_variant, Target::Variant; @@ -331,6 +331,9 @@ language_item_table! { ResultOk, sym::Ok, result_ok_variant, Target::Variant; ResultErr, sym::Err, result_err_variant, Target::Variant; + ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant; + ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant; + IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }); IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}); diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 65c99535c4e..ad2ecae9233 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -3,11 +3,10 @@ //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html #![feature(crate_visibility_modifier)] -#![feature(const_panic)] -#![feature(extended_key_value_attributes)] +#![cfg_attr(bootstrap, feature(extended_key_value_attributes))] #![feature(in_band_lifetimes)] #![feature(once_cell)] -#![cfg_attr(bootstrap, feature(or_patterns))] +#![feature(min_specialization)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs index 2aafc6afa23..4636d515249 100644 --- a/compiler/rustc_hir/src/tests.rs +++ b/compiler/rustc_hir/src/tests.rs @@ -1,6 +1,4 @@ use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData}; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_span::crate_disambiguator::CrateDisambiguator; use rustc_span::def_id::{DefPathHash, StableCrateId}; #[test] @@ -13,17 +11,16 @@ fn def_path_hash_depends_on_crate_id() { // the crate by changing the crate disambiguator (e.g. via bumping the // crate's version number). - let d0 = CrateDisambiguator::from(Fingerprint::new(12, 34)); - let d1 = CrateDisambiguator::from(Fingerprint::new(56, 78)); + let id0 = StableCrateId::new("foo", false, vec!["1".to_string()]); + let id1 = StableCrateId::new("foo", false, vec!["2".to_string()]); - let h0 = mk_test_hash("foo", d0); - let h1 = mk_test_hash("foo", d1); + let h0 = mk_test_hash(id0); + let h1 = mk_test_hash(id1); assert_ne!(h0.stable_crate_id(), h1.stable_crate_id()); assert_ne!(h0.local_hash(), h1.local_hash()); - fn mk_test_hash(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> DefPathHash { - let stable_crate_id = StableCrateId::new(crate_name, crate_disambiguator); + fn mk_test_hash(stable_crate_id: StableCrateId) -> DefPathHash { let parent_hash = DefPathHash::new(stable_crate_id, 0); let key = DefKey { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index fe02cc5de8c..2b932b7c953 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1,4 +1,3 @@ -#![cfg_attr(bootstrap, feature(or_patterns))] #![recursion_limit = "256"] use rustc_ast as ast; diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml index 049e5b8b722..85bf4dc176b 100644 --- a/compiler/rustc_incremental/Cargo.toml +++ b/compiler/rustc_incremental/Cargo.toml @@ -20,3 +20,4 @@ rustc_macros = { path = "../rustc_macros" } rustc_span = { path = "../rustc_span" } rustc_fs_util = { path = "../rustc_fs_util" } rustc_session = { path = "../rustc_session" } +rustc_errors = { path = "../rustc_errors" } diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs index e7bd488af8e..9abd4eae914 100644 --- a/compiler/rustc_incremental/src/persist/dirty_clean.rs +++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs @@ -1,6 +1,5 @@ -//! Debugging code to test fingerprints computed for query results. -//! For each node marked with `#[rustc_clean]` or `#[rustc_dirty]`, -//! we will compare the fingerprint from the current and from the previous +//! Debugging code to test fingerprints computed for query results. For each node marked with +//! `#[rustc_clean]` we will compare the fingerprint from the current and from the previous //! compilation session as appropriate: //! //! - `#[rustc_clean(cfg="rev2", except="typeck")]` if we are @@ -30,7 +29,6 @@ use std::iter::FromIterator; use std::vec::Vec; const EXCEPT: Symbol = sym::except; -const LABEL: Symbol = sym::label; const CFG: Symbol = sym::cfg; // Base and Extra labels to build up the labels @@ -102,6 +100,12 @@ const LABELS_FN_IN_TRAIT: &[&[&str]] = const LABELS_HIR_ONLY: &[&[&str]] = &[BASE_HIR]; /// Impl `DepNode`s. +const LABELS_TRAIT: &[&[&str]] = &[ + BASE_HIR, + &[label_strs::associated_item_def_ids, label_strs::predicates_of, label_strs::generics_of], +]; + +/// Impl `DepNode`s. const LABELS_IMPL: &[&[&str]] = &[BASE_HIR, BASE_IMPL]; /// Abstract data type (struct, enum, union) `DepNode`s. @@ -122,22 +126,12 @@ struct Assertion { dirty: Labels, } -impl Assertion { - fn from_clean_labels(labels: Labels) -> Assertion { - Assertion { clean: labels, dirty: Labels::default() } - } - - fn from_dirty_labels(labels: Labels) -> Assertion { - Assertion { clean: Labels::default(), dirty: labels } - } -} - pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { if !tcx.sess.opts.debugging_opts.query_dep_graph { return; } - // can't add `#[rustc_dirty]` etc without opting in to this feature + // can't add `#[rustc_clean]` etc without opting in to this feature if !tcx.features().rustc_attrs { return; } @@ -147,11 +141,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) { let mut dirty_clean_visitor = DirtyCleanVisitor { tcx, checked_attrs: Default::default() }; krate.visit_all_item_likes(&mut dirty_clean_visitor); - let mut all_attrs = FindAllAttrs { - tcx, - attr_names: &[sym::rustc_dirty, sym::rustc_clean], - found_attrs: vec![], - }; + let mut all_attrs = FindAllAttrs { tcx, found_attrs: vec![] }; intravisit::walk_crate(&mut all_attrs, krate); // Note that we cannot use the existing "unused attribute"-infrastructure @@ -169,37 +159,20 @@ pub struct DirtyCleanVisitor<'tcx> { impl DirtyCleanVisitor<'tcx> { /// Possibly "deserialize" the attribute into a clean/dirty assertion fn assertion_maybe(&mut self, item_id: LocalDefId, attr: &Attribute) -> Option<Assertion> { - let is_clean = if self.tcx.sess.check_name(attr, sym::rustc_dirty) { - false - } else if self.tcx.sess.check_name(attr, sym::rustc_clean) { - true - } else { + if !self.tcx.sess.check_name(attr, sym::rustc_clean) { // skip: not rustc_clean/dirty return None; - }; + } if !check_config(self.tcx, attr) { // skip: not the correct `cfg=` return None; } - let assertion = if let Some(labels) = self.labels(attr) { - if is_clean { - Assertion::from_clean_labels(labels) - } else { - Assertion::from_dirty_labels(labels) - } - } else { - self.assertion_auto(item_id, attr, is_clean) - }; + let assertion = self.assertion_auto(item_id, attr); Some(assertion) } /// Gets the "auto" assertion on pre-validated attr, along with the `except` labels. - fn assertion_auto( - &mut self, - item_id: LocalDefId, - attr: &Attribute, - is_clean: bool, - ) -> Assertion { + fn assertion_auto(&mut self, item_id: LocalDefId, attr: &Attribute) -> Assertion { let (name, mut auto) = self.auto_labels(item_id, attr); let except = self.except(attr); for e in except.iter() { @@ -211,21 +184,7 @@ impl DirtyCleanVisitor<'tcx> { self.tcx.sess.span_fatal(attr.span, &msg); } } - if is_clean { - Assertion { clean: auto, dirty: except } - } else { - Assertion { clean: except, dirty: auto } - } - } - - fn labels(&self, attr: &Attribute) -> Option<Labels> { - for item in attr.meta_item_list().unwrap_or_else(Vec::new) { - if item.has_name(LABEL) { - let value = expect_associated_value(self.tcx, &item); - return Some(self.resolve_labels(&item, value)); - } - } - None + Assertion { clean: auto, dirty: except } } /// `except=` attribute value @@ -288,20 +247,7 @@ impl DirtyCleanVisitor<'tcx> { HirItem::Union(..) => ("ItemUnion", LABELS_ADT), // Represents a Trait Declaration - // FIXME(michaelwoerister): trait declaration is buggy because sometimes some of - // the depnodes don't exist (because they legitimately didn't need to be - // calculated) - // - // michaelwoerister and vitiral came up with a possible solution, - // to just do this before every query - // ``` - // ::rustc_middle::ty::query::plumbing::force_from_dep_node(tcx, dep_node) - // ``` - // - // However, this did not seem to work effectively and more bugs were hit. - // Nebie @vitiral gave up :) - // - //HirItem::Trait(..) => ("ItemTrait", LABELS_TRAIT), + HirItem::Trait(..) => ("ItemTrait", LABELS_TRAIT), // An implementation, eg `impl<A> Trait for Foo { .. }` HirItem::Impl { .. } => ("ItemKind::Impl", LABELS_IMPL), @@ -434,35 +380,23 @@ impl ItemLikeVisitor<'tcx> for DirtyCleanVisitor<'tcx> { } } -/// Given a `#[rustc_dirty]` or `#[rustc_clean]` attribute, scan -/// for a `cfg="foo"` attribute and check whether we have a cfg -/// flag called `foo`. -/// -/// Also make sure that the `label` and `except` fields do not -/// both exist. +/// Given a `#[rustc_clean]` attribute, scan for a `cfg="foo"` attribute and check whether we have +/// a cfg flag called `foo`. fn check_config(tcx: TyCtxt<'_>, attr: &Attribute) -> bool { debug!("check_config(attr={:?})", attr); let config = &tcx.sess.parse_sess.config; debug!("check_config: config={:?}", config); - let (mut cfg, mut except, mut label) = (None, false, false); + let mut cfg = None; for item in attr.meta_item_list().unwrap_or_else(Vec::new) { if item.has_name(CFG) { let value = expect_associated_value(tcx, &item); debug!("check_config: searching for cfg {:?}", value); cfg = Some(config.contains(&(value, None))); - } - if item.has_name(LABEL) { - label = true; - } - if item.has_name(EXCEPT) { - except = true; + } else if !item.has_name(EXCEPT) { + tcx.sess.span_err(attr.span, &format!("unknown item `{}`", item.name_or_empty())); } } - if label && except { - tcx.sess.span_fatal(attr.span, "must specify only one of: `label`, `except`"); - } - match cfg { None => tcx.sess.span_fatal(attr.span, "no cfg attribute"), Some(c) => c, @@ -483,21 +417,18 @@ fn expect_associated_value(tcx: TyCtxt<'_>, item: &NestedMetaItem) -> Symbol { } } -// A visitor that collects all #[rustc_dirty]/#[rustc_clean] attributes from +// A visitor that collects all #[rustc_clean] attributes from // the HIR. It is used to verify that we really ran checks for all annotated // nodes. -pub struct FindAllAttrs<'a, 'tcx> { +pub struct FindAllAttrs<'tcx> { tcx: TyCtxt<'tcx>, - attr_names: &'a [Symbol], found_attrs: Vec<&'tcx Attribute>, } -impl FindAllAttrs<'_, 'tcx> { +impl FindAllAttrs<'tcx> { fn is_active_attr(&mut self, attr: &Attribute) -> bool { - for attr_name in self.attr_names { - if self.tcx.sess.check_name(attr, *attr_name) && check_config(self.tcx, attr) { - return true; - } + if self.tcx.sess.check_name(attr, sym::rustc_clean) && check_config(self.tcx, attr) { + return true; } false @@ -506,17 +437,14 @@ impl FindAllAttrs<'_, 'tcx> { fn report_unchecked_attrs(&self, mut checked_attrs: FxHashSet<ast::AttrId>) { for attr in &self.found_attrs { if !checked_attrs.contains(&attr.id) { - self.tcx.sess.span_err( - attr.span, - "found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute", - ); + self.tcx.sess.span_err(attr.span, "found unchecked `#[rustc_clean]` attribute"); checked_attrs.insert(attr.id); } } } } -impl intravisit::Visitor<'tcx> for FindAllAttrs<'_, 'tcx> { +impl intravisit::Visitor<'tcx> for FindAllAttrs<'tcx> { type Map = Map<'tcx>; fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap<Self::Map> { diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 30c6c408bc7..2ed0539841a 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -106,8 +106,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::svh::Svh; use rustc_data_structures::{base_n, flock}; +use rustc_errors::ErrorReported; use rustc_fs_util::{link_or_copy, LinkOrCopy}; -use rustc_session::{CrateDisambiguator, Session}; +use rustc_session::{Session, StableCrateId}; use std::fs as std_fs; use std::io; @@ -188,10 +189,10 @@ pub fn in_incr_comp_dir(incr_comp_session_dir: &Path, file_name: &str) -> PathBu pub fn prepare_session_directory( sess: &Session, crate_name: &str, - crate_disambiguator: CrateDisambiguator, -) { + stable_crate_id: StableCrateId, +) -> Result<(), ErrorReported> { if sess.opts.incremental.is_none() { - return; + return Ok(()); } let _timer = sess.timer("incr_comp_prepare_session_directory"); @@ -199,11 +200,9 @@ pub fn prepare_session_directory( debug!("prepare_session_directory"); // {incr-comp-dir}/{crate-name-and-disambiguator} - let crate_dir = crate_path(sess, crate_name, crate_disambiguator); + let crate_dir = crate_path(sess, crate_name, stable_crate_id); debug!("crate-dir: {}", crate_dir.display()); - if create_dir(sess, &crate_dir, "crate").is_err() { - return; - } + create_dir(sess, &crate_dir, "crate")?; // Hack: canonicalize the path *after creating the directory* // because, on windows, long paths can cause problems; @@ -217,7 +216,7 @@ pub fn prepare_session_directory( crate_dir.display(), err )); - return; + return Err(ErrorReported); } }; @@ -232,16 +231,11 @@ pub fn prepare_session_directory( // Lock the new session directory. If this fails, return an // error without retrying - let (directory_lock, lock_file_path) = match lock_directory(sess, &session_dir) { - Ok(e) => e, - Err(_) => return, - }; + let (directory_lock, lock_file_path) = lock_directory(sess, &session_dir)?; // Now that we have the lock, we can actually create the session // directory - if create_dir(sess, &session_dir, "session").is_err() { - return; - } + create_dir(sess, &session_dir, "session")?; // Find a suitable source directory to copy from. Ignore those that we // have already tried before. @@ -257,7 +251,7 @@ pub fn prepare_session_directory( ); sess.init_incr_comp_session(session_dir, directory_lock, false); - return; + return Ok(()); }; debug!("attempting to copy data from source: {}", source_directory.display()); @@ -278,7 +272,7 @@ pub fn prepare_session_directory( } sess.init_incr_comp_session(session_dir, directory_lock, true); - return; + return Ok(()); } else { debug!("copying failed - trying next directory"); @@ -478,7 +472,7 @@ fn generate_session_dir_path(crate_dir: &Path) -> PathBuf { directory_path } -fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> { +fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ErrorReported> { match std_fs::create_dir_all(path) { Ok(()) => { debug!("{} directory created successfully", dir_tag); @@ -492,13 +486,16 @@ fn create_dir(sess: &Session, path: &Path, dir_tag: &str) -> Result<(), ()> { path.display(), err )); - Err(()) + Err(ErrorReported) } } } /// Allocate the lock-file and lock it. -fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, PathBuf), ()> { +fn lock_directory( + sess: &Session, + session_dir: &Path, +) -> Result<(flock::Lock, PathBuf), ErrorReported> { let lock_file_path = lock_file_path(session_dir); debug!("lock_directory() - lock_file: {}", lock_file_path.display()); @@ -510,13 +507,36 @@ fn lock_directory(sess: &Session, session_dir: &Path) -> Result<(flock::Lock, Pa ) { // the lock should be exclusive Ok(lock) => Ok((lock, lock_file_path)), - Err(err) => { - sess.err(&format!( + Err(lock_err) => { + let mut err = sess.struct_err(&format!( "incremental compilation: could not create \ - session directory lock file: {}", - err + session directory lock file: {}", + lock_err )); - Err(()) + if flock::Lock::error_unsupported(&lock_err) { + err.note(&format!( + "the filesystem for the incremental path at {} \ + does not appear to support locking, consider changing the \ + incremental path to a filesystem that supports locking \ + or disable incremental compilation", + session_dir.display() + )); + if std::env::var_os("CARGO").is_some() { + err.help( + "incremental compilation can be disabled by setting the \ + environment variable CARGO_INCREMENTAL=0 (see \ + https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)", + ); + err.help( + "the entire build directory can be changed to a different \ + filesystem by setting the environment variable CARGO_TARGET_DIR \ + to a different path (see \ + https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)", + ); + } + } + err.emit(); + Err(ErrorReported) } } } @@ -628,19 +648,12 @@ fn string_to_timestamp(s: &str) -> Result<SystemTime, ()> { Ok(UNIX_EPOCH + duration) } -fn crate_path( - sess: &Session, - crate_name: &str, - crate_disambiguator: CrateDisambiguator, -) -> PathBuf { +fn crate_path(sess: &Session, crate_name: &str, stable_crate_id: StableCrateId) -> PathBuf { let incr_dir = sess.opts.incremental.as_ref().unwrap().clone(); - // The full crate disambiguator is really long. 64 bits of it should be - // sufficient. - let crate_disambiguator = crate_disambiguator.to_fingerprint().to_smaller_hash(); - let crate_disambiguator = base_n::encode(crate_disambiguator as u128, INT_ENCODE_BASE); + let stable_crate_id = base_n::encode(stable_crate_id.to_u64() as u128, INT_ENCODE_BASE); - let crate_name = format!("{}-{}", crate_name, crate_disambiguator); + let crate_name = format!("{}-{}", crate_name, stable_crate_id); incr_dir.join(crate_name) } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index bd3b5239f7b..303c39a39a9 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::definitions::DefPathTable; -use rustc_middle::dep_graph::{PreviousDepGraph, SerializedDepGraph, WorkProduct, WorkProductId}; +use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId}; use rustc_middle::ty::query::OnDiskCache; use rustc_serialize::opaque::Decoder; use rustc_serialize::Decodable; @@ -22,8 +22,8 @@ pub enum LoadResult<T> { Error { message: String }, } -impl LoadResult<(PreviousDepGraph, WorkProductMap)> { - pub fn open(self, sess: &Session) -> (PreviousDepGraph, WorkProductMap) { +impl LoadResult<(SerializedDepGraph, WorkProductMap)> { + pub fn open(self, sess: &Session) -> (SerializedDepGraph, WorkProductMap) { match self { LoadResult::Error { message } => { sess.warn(&message); @@ -84,7 +84,7 @@ impl<T> MaybeAsync<T> { } } -pub type DepGraphFuture = MaybeAsync<LoadResult<(PreviousDepGraph, WorkProductMap)>>; +pub type DepGraphFuture = MaybeAsync<LoadResult<(SerializedDepGraph, WorkProductMap)>>; /// Launch a thread and load the dependency graph in the background. pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { @@ -185,7 +185,7 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { let dep_graph = SerializedDepGraph::decode(&mut decoder) .expect("Error reading cached dep-graph"); - LoadResult::Ok { data: (PreviousDepGraph::new(dep_graph), prev_work_products) } + LoadResult::Ok { data: (dep_graph, prev_work_products) } } } })) diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 1484088837a..a8455854ebb 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -1,6 +1,6 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::join; -use rustc_middle::dep_graph::{DepGraph, PreviousDepGraph, WorkProduct, WorkProductId}; +use rustc_middle::dep_graph::{DepGraph, SerializedDepGraph, WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_serialize::Encodable as RustcEncodable; @@ -186,7 +186,7 @@ fn encode_query_cache(tcx: TyCtxt<'_>, encoder: &mut FileEncoder) -> FileEncodeR pub fn build_dep_graph( sess: &Session, - prev_graph: PreviousDepGraph, + prev_graph: SerializedDepGraph, prev_work_products: FxHashMap<WorkProductId, WorkProduct>, ) -> Option<DepGraph> { if sess.opts.incremental.is_none() { @@ -229,6 +229,7 @@ pub fn build_dep_graph( } Some(DepGraph::new( + &sess.prof, prev_graph, prev_work_products, encoder, diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs index 4c73b7bf612..0093fa5e562 100644 --- a/compiler/rustc_index/src/lib.rs +++ b/compiler/rustc_index/src/lib.rs @@ -1,6 +1,5 @@ #![feature(allow_internal_unstable)] #![feature(bench_black_box)] -#![feature(const_panic)] #![feature(extend_one)] #![feature(iter_zip)] #![feature(unboxed_closures)] diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs index 1b1a59a254e..246fa28d986 100644 --- a/compiler/rustc_index/src/vec.rs +++ b/compiler/rustc_index/src/vec.rs @@ -65,7 +65,7 @@ impl Idx for u32 { /// `u32::MAX`. You can also customize things like the `Debug` impl, /// what traits are derived, and so forth via the macro. #[macro_export] -#[allow_internal_unstable(step_trait, step_trait_ext, rustc_attrs)] +#[allow_internal_unstable(step_trait, rustc_attrs, trusted_step)] macro_rules! newtype_index { // ---- public rules ---- @@ -184,7 +184,7 @@ macro_rules! newtype_index { } } - unsafe impl ::std::iter::Step for $type { + impl ::std::iter::Step for $type { #[inline] fn steps_between(start: &Self, end: &Self) -> Option<usize> { <usize as ::std::iter::Step>::steps_between( @@ -204,6 +204,9 @@ macro_rules! newtype_index { } } + // Safety: The implementation of `Step` upholds all invariants. + unsafe impl ::std::iter::TrustedStep for $type {} + impl From<$type> for u32 { #[inline] fn from(v: $type) -> u32 { diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index 680f6af63f2..fb762d2deba 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -524,7 +524,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { - Ok(vec![self.tcx.original_crate_name(cnum).to_string()]) + Ok(vec![self.tcx.crate_name(cnum).to_string()]) } fn path_qualified( self, diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs index 9ffcddfae99..49359130162 100644 --- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs +++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs @@ -3,7 +3,6 @@ use self::CombineMapType::*; use self::UndoLog::*; -use super::unify_key; use super::{ InferCtxtUndoLogs, MiscVariable, RegionVariableOrigin, Rollback, Snapshot, SubregionOrigin, }; @@ -12,9 +11,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify as ut; -use rustc_data_structures::unify::UnifyKey; use rustc_hir::def_id::DefId; use rustc_index::vec::IndexVec; +use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion}; use rustc_middle::ty::ReStatic; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{ReLateBound, ReVar}; @@ -54,7 +53,7 @@ pub struct RegionConstraintStorage<'tcx> { /// code is iterating to a fixed point, because otherwise we sometimes /// would wind up with a fresh stream of region variables that have been /// equated but appear distinct. - pub(super) unification_table: ut::UnificationTableStorage<ty::RegionVid>, + pub(super) unification_table: ut::UnificationTableStorage<RegionVidKey<'tcx>>, /// a flag set to true when we perform any unifications; this is used /// to micro-optimize `take_and_reset_data` @@ -407,8 +406,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { // `RegionConstraintData` contains the relationship here. if *any_unifications { *any_unifications = false; - self.unification_table() - .reset_unifications(|vid| unify_key::RegionVidKey { min_vid: vid }); + self.unification_table().reset_unifications(|_| UnifiedRegion(None)); } data @@ -435,8 +433,8 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { ) -> RegionVid { let vid = self.var_infos.push(RegionVariableInfo { origin, universe }); - let u_vid = self.unification_table().new_key(unify_key::RegionVidKey { min_vid: vid }); - assert_eq!(vid, u_vid); + let u_vid = self.unification_table().new_key(UnifiedRegion(None)); + assert_eq!(vid, u_vid.vid); self.undo_log.push(AddVar(vid)); debug!("created new region variable {:?} in {:?} with origin {:?}", vid, universe, origin); vid @@ -498,10 +496,18 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { self.make_subregion(origin.clone(), sub, sup); self.make_subregion(origin, sup, sub); - if let (ty::ReVar(sub), ty::ReVar(sup)) = (*sub, *sup) { - debug!("make_eqregion: uniying {:?} with {:?}", sub, sup); - self.unification_table().union(sub, sup); - self.any_unifications = true; + match (sub, sup) { + (&ty::ReVar(sub), &ty::ReVar(sup)) => { + debug!("make_eqregion: unifying {:?} with {:?}", sub, sup); + self.unification_table().union(sub, sup); + self.any_unifications = true; + } + (&ty::ReVar(vid), value) | (value, &ty::ReVar(vid)) => { + debug!("make_eqregion: unifying {:?} with {:?}", vid, value); + self.unification_table().union_value(vid, UnifiedRegion(Some(value))); + self.any_unifications = true; + } + (_, _) => {} } } } @@ -617,8 +623,29 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } } - pub fn opportunistic_resolve_var(&mut self, rid: RegionVid) -> ty::RegionVid { - self.unification_table().probe_value(rid).min_vid + /// Resolves the passed RegionVid to the root RegionVid in the unification table + pub fn opportunistic_resolve_var(&mut self, rid: ty::RegionVid) -> ty::RegionVid { + self.unification_table().find(rid).vid + } + + /// If the Region is a `ReVar`, then resolves it either to the root value in + /// the unification table, if it exists, or to the root `ReVar` in the table. + /// If the Region is not a `ReVar`, just returns the Region itself. + pub fn opportunistic_resolve_region( + &mut self, + tcx: TyCtxt<'tcx>, + region: ty::Region<'tcx>, + ) -> ty::Region<'tcx> { + match region { + ty::ReVar(rid) => { + let unified_region = self.unification_table().probe_value(*rid); + unified_region.0.unwrap_or_else(|| { + let root = self.unification_table().find(*rid).vid; + tcx.reuse_or_mk_region(region, ty::ReVar(root)) + }) + } + _ => region, + } } fn combine_map(&mut self, t: CombineMapType) -> &mut CombineMap<'tcx> { @@ -673,8 +700,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { &self, value_count: usize, ) -> (Range<RegionVid>, Vec<RegionVariableOrigin>) { - let range = RegionVid::from_index(value_count as u32) - ..RegionVid::from_index(self.unification_table.len() as u32); + let range = RegionVid::from(value_count)..RegionVid::from(self.unification_table.len()); ( range.clone(), (range.start.index()..range.end.index()) @@ -696,7 +722,7 @@ impl<'tcx> RegionConstraintCollector<'_, 'tcx> { } #[inline] - fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, ty::RegionVid> { + fn unification_table(&mut self) -> super::UnificationTable<'_, 'tcx, RegionVidKey<'tcx>> { ut::UnificationTable::with_log(&mut self.storage.unification_table, self.undo_log) } } diff --git a/compiler/rustc_infer/src/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs index f41e872e004..5ad2519a93c 100644 --- a/compiler/rustc_infer/src/infer/undo_log.rs +++ b/compiler/rustc_infer/src/infer/undo_log.rs @@ -3,6 +3,7 @@ use std::marker::PhantomData; use rustc_data_structures::snapshot_vec as sv; use rustc_data_structures::undo_log::{Rollback, UndoLogs}; use rustc_data_structures::unify as ut; +use rustc_middle::infer::unify_key::RegionVidKey; use rustc_middle::ty; use crate::{ @@ -22,7 +23,7 @@ pub(crate) enum UndoLog<'tcx> { IntUnificationTable(sv::UndoLog<ut::Delegate<ty::IntVid>>), FloatUnificationTable(sv::UndoLog<ut::Delegate<ty::FloatVid>>), RegionConstraintCollector(region_constraints::UndoLog<'tcx>), - RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>), + RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>), ProjectionCache(traits::UndoLog<'tcx>), PushRegionObligation, } @@ -55,7 +56,7 @@ impl_from! { ConstUnificationTable(sv::UndoLog<ut::Delegate<ty::ConstVid<'tcx>>>), - RegionUnificationTable(sv::UndoLog<ut::Delegate<ty::RegionVid>>), + RegionUnificationTable(sv::UndoLog<ut::Delegate<RegionVidKey<'tcx>>>), ProjectionCache(traits::UndoLog<'tcx>), } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 15b4a7ed207..ee358c52c2f 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -16,13 +16,12 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(const_panic)] #![feature(extend_one)] #![feature(iter_zip)] #![feature(never_type)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(in_band_lifetimes)] #![feature(control_flow_enum)] +#![feature(min_specialization)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index f2b69da3f86..b5af2bfca35 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -1,6 +1,5 @@ #![feature(bool_to_option)] #![feature(box_patterns)] -#![feature(box_syntax)] #![feature(internal_output_capture)] #![feature(nll)] #![feature(generator_trait)] diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index e2220e3b60d..1666754d29a 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -12,7 +12,7 @@ use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_data_structures::{box_region_allow_access, declare_box_region_type, parallel}; use rustc_errors::{ErrorReported, PResult}; use rustc_expand::base::ExtCtxt; -use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::def_id::{StableCrateId, LOCAL_CRATE}; use rustc_hir::Crate; use rustc_lint::LintStore; use rustc_metadata::creader::CStore; @@ -170,9 +170,13 @@ pub fn register_plugins<'a>( let crate_types = util::collect_crate_types(sess, &krate.attrs); sess.init_crate_types(crate_types); - let disambiguator = util::compute_crate_disambiguator(sess); - sess.crate_disambiguator.set(disambiguator).expect("not yet initialized"); - rustc_incremental::prepare_session_directory(sess, &crate_name, disambiguator); + let stable_crate_id = StableCrateId::new( + crate_name, + sess.crate_types().contains(&CrateType::Executable), + sess.opts.cg.metadata.clone(), + ); + sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized"); + rustc_incremental::prepare_session_directory(sess, &crate_name, stable_crate_id)?; if sess.opts.incremental.is_some() { sess.time("incr_comp_garbage_collect_session_directories", || { @@ -795,7 +799,7 @@ pub fn create_global_ctxt<'tcx>( query_result_on_disk_cache, queries.as_dyn(), &crate_name, - &outputs, + outputs, ) }) }); @@ -873,9 +877,8 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { sess.time("MIR_effect_checking", || { for def_id in tcx.body_owners() { - if tcx.sess.opts.debugging_opts.thir_unsafeck { - tcx.ensure().thir_check_unsafety(def_id); - } else { + tcx.ensure().thir_check_unsafety(def_id); + if !tcx.sess.opts.debugging_opts.thir_unsafeck { mir::transform::check_unsafety::check_unsafety(tcx, def_id); } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 92d05e48068..969b526235b 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -148,7 +148,7 @@ impl<'tcx> Queries<'tcx> { self.compiler.register_lints.as_deref().unwrap_or_else(|| empty), krate, &crate_name, - ); + )?; // Compute the dependency graph (in the background). We want to do // this as early as possible, to give the DepGraph maximum time to @@ -157,7 +157,7 @@ impl<'tcx> Queries<'tcx> { // called, which happens within passes::register_plugins(). self.dep_graph_future().ok(); - result + Ok(result) }) } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index bea7d0fb81f..5d8a6084f2e 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -252,7 +252,8 @@ fn test_lints_tracking_hash_different_construction_order() { (String::from("d"), Level::Forbid), ]; - assert_same_hash(&v1, &v2); + // The hash should be order-dependent + assert_different_hash(&v1, &v2); } #[test] @@ -491,9 +492,10 @@ fn test_native_libs_tracking_hash_different_order() { }, ]; - assert_same_hash(&v1, &v2); - assert_same_hash(&v1, &v3); - assert_same_hash(&v2, &v3); + // The hash should be order-dependent + assert_different_hash(&v1, &v2); + assert_different_hash(&v1, &v3); + assert_different_hash(&v2, &v3); } #[test] diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 7b1660b501b..15cda299208 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -2,11 +2,9 @@ use rustc_ast::mut_visit::{visit_clobber, MutVisitor, *}; use rustc_ast::ptr::P; use rustc_ast::{self as ast, AttrVec, BlockCheckMode}; use rustc_codegen_ssa::traits::CodegenBackend; -use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; #[cfg(parallel_compiler)] use rustc_data_structures::jobserver; -use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync::Lrc; use rustc_errors::registry::Registry; use rustc_metadata::dynamic_lib::DynamicLibrary; @@ -18,7 +16,6 @@ use rustc_session::config::{self, CrateType}; use rustc_session::config::{ErrorOutputType, Input, OutputFilenames}; use rustc_session::lint::{self, BuiltinLintDiagnostics, LintBuffer}; use rustc_session::parse::CrateConfig; -use rustc_session::CrateDisambiguator; use rustc_session::{early_error, filesearch, output, DiagnosticOutput, Session}; use rustc_span::edition::Edition; use rustc_span::lev_distance::find_best_match_for_name; @@ -496,39 +493,6 @@ pub fn get_codegen_sysroot( } } -pub(crate) fn compute_crate_disambiguator(session: &Session) -> CrateDisambiguator { - use std::hash::Hasher; - - // The crate_disambiguator is a 128 bit hash. The disambiguator is fed - // into various other hashes quite a bit (symbol hashes, incr. comp. hashes, - // debuginfo type IDs, etc), so we don't want it to be too wide. 128 bits - // should still be safe enough to avoid collisions in practice. - let mut hasher = StableHasher::new(); - - let mut metadata = session.opts.cg.metadata.clone(); - // We don't want the crate_disambiguator to dependent on the order - // -C metadata arguments, so sort them: - metadata.sort(); - // Every distinct -C metadata value is only incorporated once: - metadata.dedup(); - - hasher.write(b"metadata"); - for s in &metadata { - // Also incorporate the length of a metadata string, so that we generate - // different values for `-Cmetadata=ab -Cmetadata=c` and - // `-Cmetadata=a -Cmetadata=bc` - hasher.write_usize(s.len()); - hasher.write(s.as_bytes()); - } - - // Also incorporate crate type, so that we don't get symbol conflicts when - // linking against a library of the same name, if this is an executable. - let is_exe = session.crate_types().contains(&CrateType::Executable); - hasher.write(if is_exe { b"exe" } else { b"lib" }); - - CrateDisambiguator::from(hasher.finish::<Fingerprint>()) -} - pub(crate) fn check_attr_crate_type( sess: &Session, attrs: &[ast::Attribute], diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index c1d6a4f1de1..a8df1b0952c 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -334,8 +334,14 @@ impl LintStore { } } - /// Checks the validity of lint names derived from the command line - pub fn check_lint_name_cmdline(&self, sess: &Session, lint_name: &str, level: Level) { + /// Checks the validity of lint names derived from the command line. Returns + /// true if the lint is valid, false otherwise. + pub fn check_lint_name_cmdline( + &self, + sess: &Session, + lint_name: &str, + level: Option<Level>, + ) -> bool { let db = match self.check_lint_name(lint_name, None) { CheckLintNameResult::Ok(_) => None, CheckLintNameResult::Warning(ref msg, _) => Some(sess.struct_warn(msg)), @@ -361,18 +367,23 @@ impl LintStore { }; if let Some(mut db) = db { - let msg = format!( - "requested on the command line with `{} {}`", - match level { - Level::Allow => "-A", - Level::Warn => "-W", - Level::Deny => "-D", - Level::Forbid => "-F", - }, - lint_name - ); - db.note(&msg); + if let Some(level) = level { + let msg = format!( + "requested on the command line with `{} {}`", + match level { + Level::Allow => "-A", + Level::Warn => "-W", + Level::Deny => "-D", + Level::Forbid => "-F", + }, + lint_name + ); + db.note(&msg); + } db.emit(); + false + } else { + true } } @@ -922,7 +933,7 @@ impl<'tcx> LateContext<'tcx> { } fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { - Ok(vec![self.tcx.original_crate_name(cnum)]) + Ok(vec![self.tcx.crate_name(cnum)]) } fn path_qualified( diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 91cdef9b089..0ee434f5fb5 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -88,7 +88,7 @@ impl<'s> LintLevelsBuilder<'s> { self.sets.lint_cap = sess.opts.lint_cap.unwrap_or(Level::Forbid); for &(ref lint_name, level) in &sess.opts.lint_opts { - store.check_lint_name_cmdline(sess, &lint_name, level); + store.check_lint_name_cmdline(sess, &lint_name, Some(level)); let orig_level = level; // If the cap is less than this specified level, e.g., if we've got @@ -109,6 +109,16 @@ impl<'s> LintLevelsBuilder<'s> { } } + for lint_name in &sess.opts.force_warns { + let valid = store.check_lint_name_cmdline(sess, lint_name, None); + if valid { + let lints = store + .find_lints(lint_name) + .unwrap_or_else(|_| bug!("A valid lint failed to produce a lint ids")); + self.sets.force_warns.extend(&lints); + } + } + self.sets.list.push(LintSet::CommandLine { specs }); } @@ -142,6 +152,9 @@ impl<'s> LintLevelsBuilder<'s> { LintLevelSource::Default => false, LintLevelSource::Node(symbol, _, _) => self.store.is_lint_group(symbol), LintLevelSource::CommandLine(symbol, _) => self.store.is_lint_group(symbol), + LintLevelSource::ForceWarn(_symbol) => { + bug!("forced warn lint returned a forbid lint level") + } }; debug!( "fcw_warning={:?}, specs.get(&id) = {:?}, old_src={:?}, id_name={:?}", @@ -166,6 +179,7 @@ impl<'s> LintLevelsBuilder<'s> { LintLevelSource::CommandLine(_, _) => { diag_builder.note("`forbid` lint level was set on command line"); } + _ => bug!("forced warn lint returned a forbid lint level"), } diag_builder.emit(); }; diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 2f46969b021..4f59460aa82 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -36,9 +36,6 @@ #![feature(iter_zip)] #![feature(never_type)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] -#![feature(half_open_range_patterns)] -#![feature(exclusive_range_pattern)] #![feature(control_flow_enum)] #![recursion_limit = "256"] diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs index be9c6eafb6f..7146dd51aa7 100644 --- a/compiler/rustc_lint/src/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -176,6 +176,7 @@ impl EarlyLintPass for NonCamelCaseTypes { | ast::ItemKind::Struct(..) | ast::ItemKind::Union(..) => self.check_case(cx, "type", &it.ident), ast::ItemKind::Trait(..) => self.check_case(cx, "trait", &it.ident), + ast::ItemKind::TraitAlias(..) => self.check_case(cx, "trait alias", &it.ident), _ => (), } } diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs index 9c94bab04e9..319adf42cf1 100644 --- a/compiler/rustc_lint/src/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -5,7 +5,6 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::{is_range_literal, ExprKind, Node}; -use rustc_index::vec::Idx; use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; @@ -13,7 +12,7 @@ use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::Abi; -use rustc_target::abi::{Integer, LayoutOf, TagEncoding, VariantIdx, Variants}; +use rustc_target::abi::{Integer, LayoutOf, TagEncoding, Variants}; use rustc_target::spec::abi::Abi as SpecAbi; use std::cmp; @@ -783,25 +782,14 @@ crate fn repr_nullable_ptr<'tcx>( ) -> Option<Ty<'tcx>> { debug!("is_repr_nullable_ptr(cx, ty = {:?})", ty); if let ty::Adt(ty_def, substs) = ty.kind() { - if ty_def.variants.len() != 2 { - return None; - } - - let get_variant_fields = |index| &ty_def.variants[VariantIdx::new(index)].fields; - let variant_fields = [get_variant_fields(0), get_variant_fields(1)]; - let fields = if variant_fields[0].is_empty() { - &variant_fields[1] - } else if variant_fields[1].is_empty() { - &variant_fields[0] - } else { - return None; + let field_ty = match &ty_def.variants.raw[..] { + [var_one, var_two] => match (&var_one.fields[..], &var_two.fields[..]) { + ([], [field]) | ([field], []) => field.ty(cx.tcx, substs), + _ => return None, + }, + _ => return None, }; - if fields.len() != 1 { - return None; - } - - let field_ty = fields[0].ty(cx.tcx, substs); if !ty_is_known_nonnull(cx, field_ty, ckind) { return None; } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 70475563a4a..f1c4e5fb4a3 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -25,7 +25,11 @@ macro_rules! pluralize { /// before applying the suggestion. #[derive(Copy, Clone, Debug, PartialEq, Hash, Encodable, Decodable)] pub enum Applicability { - /// The suggestion is definitely what the user intended. This suggestion should be + /// The suggestion is definitely what the user intended, or maintains the exact meaning of the code. + /// This suggestion should be automatically applied. + /// + /// In case of multiple `MachineApplicable` suggestions (whether as part of + /// the same `multipart_suggestion` or not), all of them should be /// automatically applied. MachineApplicable, diff --git a/compiler/rustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml index 7a34788de91..3fca2e1ccb9 100644 --- a/compiler/rustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -13,4 +13,4 @@ libc = "0.2.73" [build-dependencies] build_helper = { path = "../../src/build_helper" } -cc = "1.0.67" +cc = "1.0.68" diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 99ce13a6ed5..3595e37cf96 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -793,16 +793,23 @@ LLVMRustOptimizeWithNewPassManager( PGOOpt = PGOOptions(PGOUsePath, "", "", PGOOptions::IRUse); } -#if LLVM_VERSION_GE(12, 0) +#if LLVM_VERSION_GE(12, 0) && !LLVM_VERSION_GE(13,0) PassBuilder PB(DebugPassManager, TM, PTO, PGOOpt, &PIC); #else PassBuilder PB(TM, PTO, PGOOpt, &PIC); #endif +#if LLVM_VERSION_GE(13, 0) + LoopAnalysisManager LAM; + FunctionAnalysisManager FAM; + CGSCCAnalysisManager CGAM; + ModuleAnalysisManager MAM; +#else LoopAnalysisManager LAM(DebugPassManager); FunctionAnalysisManager FAM(DebugPassManager); CGSCCAnalysisManager CGAM(DebugPassManager); ModuleAnalysisManager MAM(DebugPassManager); +#endif FAM.registerPass([&] { return PB.buildDefaultAAPipeline(); }); @@ -956,7 +963,11 @@ LLVMRustOptimizeWithNewPassManager( } } +#if LLVM_VERSION_GE(13, 0) + ModulePassManager MPM; +#else ModulePassManager MPM(DebugPassManager); +#endif bool NeedThinLTOBufferPasses = UseThinLTOBuffers; if (!NoPrepopulatePasses) { if (OptLevel == PassBuilder::OptimizationLevel::O0) { diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index e9ae22f8ced..42c32219aba 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -21,7 +21,7 @@ use rustc_session::config::{self, CrateType, ExternLocation}; use rustc_session::lint::{self, BuiltinLintDiagnostics, ExternDepSpec}; use rustc_session::output::validate_crate_name; use rustc_session::search_paths::PathKind; -use rustc_session::{CrateDisambiguator, Session}; +use rustc_session::Session; use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{Span, DUMMY_SP}; @@ -222,10 +222,8 @@ impl<'a> CrateLoader<'a> { metadata_loader: &'a MetadataLoaderDyn, local_crate_name: &str, ) -> Self { - let local_crate_stable_id = - StableCrateId::new(local_crate_name, sess.local_crate_disambiguator()); let mut stable_crate_ids = FxHashMap::default(); - stable_crate_ids.insert(local_crate_stable_id, LOCAL_CRATE); + stable_crate_ids.insert(sess.local_stable_crate_id(), LOCAL_CRATE); CrateLoader { sess, @@ -327,17 +325,14 @@ impl<'a> CrateLoader<'a> { fn verify_no_symbol_conflicts(&self, root: &CrateRoot<'_>) -> Result<(), CrateError> { // Check for (potential) conflicts with the local crate - if self.local_crate_name == root.name() - && self.sess.local_crate_disambiguator() == root.disambiguator() - { + if self.sess.local_stable_crate_id() == root.stable_crate_id() { return Err(CrateError::SymbolConflictsCurrent(root.name())); } // Check for conflicts with any crate loaded so far let mut res = Ok(()); self.cstore.iter_crate_data(|_, other| { - if other.name() == root.name() && // same crate-name - other.disambiguator() == root.disambiguator() && // same crate-disambiguator + if other.stable_crate_id() == root.stable_crate_id() && // same stable crate id other.hash() != root.hash() { // but different SVH @@ -411,7 +406,7 @@ impl<'a> CrateLoader<'a> { None => (&source, &crate_root), }; let dlsym_dylib = dlsym_source.dylib.as_ref().expect("no dylib for a proc-macro crate"); - Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.disambiguator())?) + Some(self.dlsym_proc_macros(&dlsym_dylib.0, dlsym_root.stable_crate_id())?) } else { None }; @@ -664,7 +659,7 @@ impl<'a> CrateLoader<'a> { fn dlsym_proc_macros( &self, path: &Path, - disambiguator: CrateDisambiguator, + stable_crate_id: StableCrateId, ) -> Result<&'static [ProcMacro], CrateError> { // Make sure the path contains a / or the linker will search for it. let path = env::current_dir().unwrap().join(path); @@ -673,7 +668,7 @@ impl<'a> CrateLoader<'a> { Err(s) => return Err(CrateError::DlOpen(s)), }; - let sym = self.sess.generate_proc_macro_decls_symbol(disambiguator); + let sym = self.sess.generate_proc_macro_decls_symbol(stable_crate_id); let decls = unsafe { let sym = match lib.symbol(&sym) { Ok(f) => f, diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index c4d9e3f77f0..27842ac7796 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,14 +1,11 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(core_intrinsics)] #![feature(crate_visibility_modifier)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(once_cell)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(proc_macro_internals)] #![feature(min_specialization)] -#![feature(stmt_expr_attributes)] #![feature(try_blocks)] #![feature(never_type)] #![recursion_limit = "256"] diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index 6e736095090..b830c6b2481 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -226,7 +226,7 @@ use rustc_session::config::{self, CrateType}; use rustc_session::filesearch::{FileDoesntMatch, FileMatches, FileSearch}; use rustc_session::search_paths::PathKind; use rustc_session::utils::CanonicalizedPath; -use rustc_session::{CrateDisambiguator, Session}; +use rustc_session::{Session, StableCrateId}; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use rustc_target::spec::{Target, TargetTriple}; @@ -787,7 +787,7 @@ pub fn find_plugin_registrar( metadata_loader: &dyn MetadataLoader, span: Span, name: Symbol, -) -> (PathBuf, CrateDisambiguator) { +) -> (PathBuf, StableCrateId) { match find_plugin_registrar_impl(sess, metadata_loader, name) { Ok(res) => res, // `core` is always available if we got as far as loading plugins. @@ -799,7 +799,7 @@ fn find_plugin_registrar_impl<'a>( sess: &'a Session, metadata_loader: &dyn MetadataLoader, name: Symbol, -) -> Result<(PathBuf, CrateDisambiguator), CrateError> { +) -> Result<(PathBuf, StableCrateId), CrateError> { info!("find plugin registrar `{}`", name); let mut locator = CrateLocator::new( sess, @@ -816,7 +816,7 @@ fn find_plugin_registrar_impl<'a>( match locator.maybe_load_library_crate()? { Some(library) => match library.source.dylib { - Some(dylib) => Ok((dylib.0, library.metadata.get_root().disambiguator())), + Some(dylib) => Ok((dylib.0, library.metadata.get_root().stable_crate_id())), None => Err(CrateError::NonDylibPlugin(name)), }, None => Err(locator.into_error()), diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index b27eef376c4..59fec58f0a1 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -300,7 +300,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for DecodeContext<'a, 'tcx> { { let tcx = self.tcx(); - let key = ty::CReaderCacheKey { cnum: self.cdata().cnum, pos: shorthand }; + let key = ty::CReaderCacheKey { cnum: Some(self.cdata().cnum), pos: shorthand }; if let Some(&ty) = tcx.ty_rcache.borrow().get(&key) { return Ok(ty); @@ -620,10 +620,6 @@ impl CrateRoot<'_> { self.name } - crate fn disambiguator(&self) -> CrateDisambiguator { - self.disambiguator - } - crate fn hash(&self) -> Svh { self.hash } @@ -1927,14 +1923,18 @@ impl CrateMetadata { self.root.name } - crate fn disambiguator(&self) -> CrateDisambiguator { - self.root.disambiguator + crate fn stable_crate_id(&self) -> StableCrateId { + self.root.stable_crate_id } crate fn hash(&self) -> Svh { self.root.hash } + fn num_def_ids(&self) -> usize { + self.root.tables.def_keys.size() + } + fn local_def_id(&self, index: DefIndex) -> DefId { DefId { krate: self.cnum, index } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index e25b22c8331..9e615e48a3c 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -19,7 +19,7 @@ use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, Visibility}; use rustc_session::utils::NativeLibKind; -use rustc_session::{CrateDisambiguator, Session}; +use rustc_session::{Session, StableCrateId}; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Symbol; @@ -155,6 +155,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) } dylib_dependency_formats => { cdata.get_dylib_dependency_formats(tcx) } + is_private_dep => { cdata.private_dep } is_panic_runtime => { cdata.root.panic_runtime } is_compiler_builtins => { cdata.root.compiler_builtins } has_global_allocator => { cdata.root.has_global_allocator } @@ -185,10 +186,9 @@ provide! { <'tcx> tcx, def_id, other, cdata, } native_libraries => { Lrc::new(cdata.get_native_libraries(tcx.sess)) } foreign_modules => { cdata.get_foreign_modules(tcx) } - crate_disambiguator => { cdata.root.disambiguator } crate_hash => { cdata.root.hash } crate_host_hash => { cdata.host_hash } - original_crate_name => { cdata.root.name } + crate_name => { cdata.root.name } extra_filename => { cdata.root.extra_filename.clone() } @@ -205,7 +205,6 @@ provide! { <'tcx> tcx, def_id, other, cdata, let r = *cdata.dep_kind.lock(); r } - crate_name => { cdata.root.name } item_children => { let mut result = SmallVec::<[_; 8]>::new(); cdata.each_child_of_item(def_id.index, |child| result.push(child), tcx.sess); @@ -251,6 +250,10 @@ pub fn provide(providers: &mut Providers) { is_statically_included_foreign_item: |tcx, id| { matches!(tcx.native_library_kind(id), Some(NativeLibKind::Static { .. })) }, + is_private_dep: |_tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + false + }, native_library_kind: |tcx, id| { tcx.native_libraries(id.krate) .iter() @@ -455,6 +458,13 @@ impl CStore { self.get_crate_data(def_id.krate).module_expansion(def_id.index, sess) } + /// Only public-facing way to traverse all the definitions in a non-local crate. + /// Critically useful for this third-party project: <https://github.com/hacspec/hacspec>. + /// See <https://github.com/rust-lang/rust/pull/85889> for context. + pub fn num_def_ids_untracked(&self, cnum: CrateNum) -> usize { + self.get_crate_data(cnum).num_def_ids() + } + pub fn item_attrs(&self, def_id: DefId, sess: &Session) -> Vec<ast::Attribute> { self.get_crate_data(def_id.krate).get_item_attrs(def_id.index, sess).collect() } @@ -478,12 +488,8 @@ impl CrateStore for CStore { self.get_crate_data(cnum).root.name } - fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool { - self.get_crate_data(cnum).private_dep - } - - fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator { - self.get_crate_data(cnum).root.disambiguator + fn stable_crate_id_untracked(&self, cnum: CrateNum) -> StableCrateId { + self.get_crate_data(cnum).root.stable_crate_id } fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 0c31430598a..2fd9a46cf42 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -671,7 +671,6 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { extra_filename: tcx.sess.opts.cg.extra_filename.clone(), triple: tcx.sess.opts.target_triple.clone(), hash: tcx.crate_hash(LOCAL_CRATE), - disambiguator: tcx.sess.local_crate_disambiguator(), stable_crate_id: tcx.def_path_hash(LOCAL_CRATE.as_def_id()).stable_crate_id(), panic_strategy: tcx.sess.panic_strategy(), edition: tcx.sess.edition(), @@ -1674,7 +1673,7 @@ impl EncodeContext<'a, 'tcx> { .iter() .map(|&cnum| { let dep = CrateDep { - name: self.tcx.original_crate_name(cnum), + name: self.tcx.crate_name(cnum), hash: self.tcx.crate_hash(cnum), host_hash: self.tcx.crate_host_hash(cnum), kind: self.tcx.dep_kind(cnum), diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 04fe5cf5890..9a3a6284c36 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -18,7 +18,6 @@ use rustc_middle::mir; use rustc_middle::ty::{self, ReprOptions, Ty}; use rustc_serialize::opaque::Encoder; use rustc_session::config::SymbolManglingVersion; -use rustc_session::CrateDisambiguator; use rustc_span::edition::Edition; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{Ident, Symbol}; @@ -202,7 +201,6 @@ crate struct CrateRoot<'tcx> { triple: TargetTriple, extra_filename: String, hash: Svh, - disambiguator: CrateDisambiguator, stable_crate_id: StableCrateId, panic_strategy: PanicStrategy, edition: Edition, diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs index d5697513eef..a89d00e26ac 100644 --- a/compiler/rustc_middle/src/arena.rs +++ b/compiler/rustc_middle/src/arena.rs @@ -14,6 +14,7 @@ macro_rules! arena_types { [] layouts: rustc_target::abi::Layout, // AdtDef are interned and compared by address [] adt_def: rustc_middle::ty::AdtDef, + [] steal_thir: rustc_data_structures::steal::Steal<rustc_middle::thir::Thir<$tcx>>, [] steal_mir: rustc_data_structures::steal::Steal<rustc_middle::mir::Body<$tcx>>, [decode] mir: rustc_middle::mir::Body<$tcx>, [] steal_promoted: diff --git a/compiler/rustc_middle/src/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs index 31bea832958..aa61219ad78 100644 --- a/compiler/rustc_middle/src/dep_graph/mod.rs +++ b/compiler/rustc_middle/src/dep_graph/mod.rs @@ -18,7 +18,6 @@ crate use dep_node::{make_compile_codegen_unit, make_compile_mono_item}; pub type DepGraph = rustc_query_system::dep_graph::DepGraph<DepKind>; pub type TaskDeps = rustc_query_system::dep_graph::TaskDeps<DepKind>; pub type DepGraphQuery = rustc_query_system::dep_graph::DepGraphQuery<DepKind>; -pub type PreviousDepGraph = rustc_query_system::dep_graph::PreviousDepGraph<DepKind>; pub type SerializedDepGraph = rustc_query_system::dep_graph::SerializedDepGraph<DepKind>; pub type EdgeFilter = rustc_query_system::dep_graph::debug::EdgeFilter<DepKind>; diff --git a/compiler/rustc_middle/src/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs index 342cc9a7397..8ffd98326f1 100644 --- a/compiler/rustc_middle/src/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -1,6 +1,6 @@ use crate::arena::Arena; -use crate::hir::map::{HirOwnerData, Map}; -use crate::hir::{IndexedHir, Owner, OwnerNodes, ParentedNode}; +use crate::hir::map::Map; +use crate::hir::{IndexedHir, OwnerNodes, ParentedNode}; use crate::ich::StableHashingContext; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -28,7 +28,7 @@ pub(super) struct NodeCollector<'a, 'hir> { /// Source map source_map: &'a SourceMap, - map: IndexVec<LocalDefId, HirOwnerData<'hir>>, + map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>, parenting: FxHashMap<LocalDefId, HirId>, /// The parent of this node @@ -107,9 +107,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { current_dep_node_owner: LocalDefId { local_def_index: CRATE_DEF_INDEX }, definitions, hcx, - map: (0..definitions.def_index_count()) - .map(|_| HirOwnerData { signature: None, with_bodies: None }) - .collect(), + map: IndexVec::from_fn_n(|_| None, definitions.def_index_count()), parenting: FxHashMap::default(), }; collector.insert_entry( @@ -124,7 +122,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { pub(super) fn finalize_and_compute_crate_hash(mut self) -> IndexedHir<'hir> { // Insert bodies into the map for (id, body) in self.krate.bodies.iter() { - let bodies = &mut self.map[id.hir_id.owner].with_bodies.as_mut().unwrap().bodies; + let bodies = &mut self.map[id.hir_id.owner].as_mut().unwrap().bodies; assert!(bodies.insert(id.hir_id.local_id, body).is_none()); } IndexedHir { map: self.map, parenting: self.parenting } @@ -137,22 +135,13 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { let data = &mut self.map[id.owner]; - if data.with_bodies.is_none() { - data.with_bodies = Some(arena.alloc(OwnerNodes { + if i == 0 { + debug_assert!(data.is_none()); + *data = Some(arena.alloc(OwnerNodes { hash, nodes: IndexVec::new(), bodies: FxHashMap::default(), })); - } - - let nodes = data.with_bodies.as_mut().unwrap(); - - if i == 0 { - // Overwrite the dummy hash with the real HIR owner hash. - nodes.hash = hash; - - debug_assert!(data.signature.is_none()); - data.signature = Some(self.arena.alloc(Owner { node: entry.node })); let dk_parent = self.definitions.def_key(id.owner).parent; if let Some(dk_parent) = dk_parent { @@ -168,13 +157,16 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { debug_assert_eq!(self.parenting.get(&id.owner), Some(&entry.parent)); } } else { - assert_eq!(entry.parent.owner, id.owner); - insert_vec_map( - &mut nodes.nodes, - id.local_id, - ParentedNode { parent: entry.parent.local_id, node: entry.node }, - ); + debug_assert_eq!(entry.parent.owner, id.owner); } + + let data = data.as_mut().unwrap(); + + insert_vec_map( + &mut data.nodes, + id.local_id, + ParentedNode { parent: entry.parent.local_id, node: entry.node }, + ); } fn insert(&mut self, span: Span, hir_id: HirId, node: Node<'hir>) { diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index d154b7804f0..07b39c97c49 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,6 +1,6 @@ use self::collector::NodeCollector; -use crate::hir::{AttributeMap, HirOwnerData, IndexedHir}; +use crate::hir::{AttributeMap, IndexedHir}; use crate::middle::cstore::CrateStore; use crate::ty::TyCtxt; use rustc_ast as ast; @@ -15,6 +15,7 @@ use rustc_hir::intravisit::Visitor; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::*; use rustc_index::vec::Idx; +use rustc_span::def_id::StableCrateId; use rustc_span::hygiene::MacroKind; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, Ident, Symbol}; @@ -952,7 +953,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { .filter_map(|(def_id, hod)| { let def_path_hash = tcx.definitions.def_path_hash(def_id); let mut hasher = StableHasher::new(); - hod.with_bodies.as_ref()?.hash_stable(&mut hcx, &mut hasher); + hod.as_ref()?.hash_stable(&mut hcx, &mut hasher); AttributeMap { map: &tcx.untracked_crate.attrs, prefix: def_id } .hash_stable(&mut hcx, &mut hasher); Some((def_path_hash, hasher.finish())) @@ -990,25 +991,24 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Svh { upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); source_file_names.hash_stable(&mut hcx, &mut stable_hasher); tcx.sess.opts.dep_tracking_hash(true).hash_stable(&mut hcx, &mut stable_hasher); - tcx.sess.local_crate_disambiguator().to_fingerprint().hash_stable(&mut hcx, &mut stable_hasher); + tcx.sess.local_stable_crate_id().hash_stable(&mut hcx, &mut stable_hasher); tcx.untracked_crate.non_exported_macro_attrs.hash_stable(&mut hcx, &mut stable_hasher); let crate_hash: Fingerprint = stable_hasher.finish(); Svh::new(crate_hash.to_smaller_hash()) } -fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(Symbol, Fingerprint, Svh)> { +fn upstream_crates(cstore: &dyn CrateStore) -> Vec<(StableCrateId, Svh)> { let mut upstream_crates: Vec<_> = cstore .crates_untracked() .iter() .map(|&cnum| { - let name = cstore.crate_name_untracked(cnum); - let disambiguator = cstore.crate_disambiguator_untracked(cnum).to_fingerprint(); + let stable_crate_id = cstore.stable_crate_id_untracked(cnum); let hash = cstore.crate_hash_untracked(cnum); - (name, disambiguator, hash) + (stable_crate_id, hash) }) .collect(); - upstream_crates.sort_unstable_by_key(|&(name, dis, _)| (name.as_str(), dis)); + upstream_crates.sort_unstable_by_key(|&(stable_crate_id, _)| stable_crate_id); upstream_crates } diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 879372c65ea..b8407833c90 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -15,23 +15,25 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_hir::def_id::LocalDefId; use rustc_hir::*; -use rustc_index::vec::IndexVec; +use rustc_index::vec::{Idx, IndexVec}; use rustc_span::DUMMY_SP; use std::collections::BTreeMap; -#[derive(Debug)] -struct HirOwnerData<'hir> { - signature: Option<&'hir Owner<'hir>>, - with_bodies: Option<&'hir mut OwnerNodes<'hir>>, -} - +/// Result of HIR indexing. #[derive(Debug)] pub struct IndexedHir<'hir> { - map: IndexVec<LocalDefId, HirOwnerData<'hir>>, + /// Contents of the HIR owned by each definition. None for definitions that are not HIR owners. + // The `mut` comes from construction time, and is harmless since we only ever hand out + // immutable refs to IndexedHir. + map: IndexVec<LocalDefId, Option<&'hir mut OwnerNodes<'hir>>>, + /// Map from each owner to its parent's HirId inside another owner. + // This map is separate from `map` to eventually allow for per-owner indexing. parenting: FxHashMap<LocalDefId, HirId>, } -#[derive(Debug)] +/// Top-level HIR node for current owner. This only contains the node for which +/// `HirId::local_id == 0`, and excludes bodies. +#[derive(Copy, Clone, Debug)] pub struct Owner<'tcx> { node: Node<'tcx>, } @@ -43,6 +45,9 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for Owner<'tcx> { } } +/// HIR node coupled with its parent's id in the same HIR owner. +/// +/// The parent is trash when the node is a HIR owner. #[derive(Clone, Debug)] pub struct ParentedNode<'tcx> { parent: ItemLocalId, @@ -51,8 +56,12 @@ pub struct ParentedNode<'tcx> { #[derive(Debug)] pub struct OwnerNodes<'tcx> { + /// Pre-computed hash of the full HIR. hash: Fingerprint, + /// Full HIR for the current owner. + // The zeroth node's parent is trash, but is never accessed. nodes: IndexVec<ItemLocalId, Option<ParentedNode<'tcx>>>, + /// Content of local bodies. bodies: FxHashMap<ItemLocalId, &'tcx Body<'tcx>>, } @@ -65,6 +74,8 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for OwnerNodes<'tcx> { } } +/// Attributes owner by a HIR owner. It is build as a slice inside the attributes map, restricted +/// to the nodes whose `HirId::owner` is `prefix`. #[derive(Copy, Clone)] pub struct AttributeMap<'tcx> { map: &'tcx BTreeMap<HirId, &'tcx [Attribute]>, @@ -127,8 +138,12 @@ pub fn provide(providers: &mut Providers) { providers.index_hir = map::index_hir; providers.crate_hash = map::crate_hash; providers.hir_module_items = |tcx, id| &tcx.untracked_crate.modules[&id]; - providers.hir_owner = |tcx, id| tcx.index_hir(()).map[id].signature; - providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].with_bodies.as_deref(); + providers.hir_owner = |tcx, id| { + let owner = tcx.index_hir(()).map[id].as_ref()?; + let node = owner.nodes[ItemLocalId::new(0)].as_ref()?.node; + Some(Owner { node }) + }; + providers.hir_owner_nodes = |tcx, id| tcx.index_hir(()).map[id].as_deref(); providers.hir_owner_parent = |tcx, id| { let index = tcx.index_hir(()); index.parenting.get(&id).copied().unwrap_or(CRATE_HIR_ID) diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 5df2f91f09f..d764d45ba7e 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -294,6 +294,7 @@ TrivialTypeFoldableImpls! { } impl<'tcx> CanonicalVarValues<'tcx> { + #[inline] pub fn len(&self) -> usize { self.var_values.len() } diff --git a/compiler/rustc_middle/src/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs index 641cf23781e..0b05dd5c0ba 100644 --- a/compiler/rustc_middle/src/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -16,37 +16,48 @@ pub trait ToType { } #[derive(PartialEq, Copy, Clone, Debug)] -pub struct RegionVidKey { - /// The minimum region vid in the unification set. This is needed - /// to have a canonical name for a type to prevent infinite - /// recursion. - pub min_vid: ty::RegionVid, -} - -impl UnifyValue for RegionVidKey { - type Error = NoError; +pub struct UnifiedRegion<'tcx>(pub Option<ty::Region<'tcx>>); - fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> { - let min_vid = if value1.min_vid.index() < value2.min_vid.index() { - value1.min_vid - } else { - value2.min_vid - }; +#[derive(PartialEq, Copy, Clone, Debug)] +pub struct RegionVidKey<'tcx> { + pub vid: ty::RegionVid, + pub phantom: PhantomData<UnifiedRegion<'tcx>>, +} - Ok(RegionVidKey { min_vid }) +impl<'tcx> From<ty::RegionVid> for RegionVidKey<'tcx> { + fn from(vid: ty::RegionVid) -> Self { + RegionVidKey { vid, phantom: PhantomData } } } -impl UnifyKey for ty::RegionVid { - type Value = RegionVidKey; +impl<'tcx> UnifyKey for RegionVidKey<'tcx> { + type Value = UnifiedRegion<'tcx>; fn index(&self) -> u32 { - u32::from(*self) + self.vid.as_u32() } - fn from_index(i: u32) -> ty::RegionVid { - ty::RegionVid::from(i) + fn from_index(i: u32) -> Self { + RegionVidKey::from(ty::RegionVid::from_u32(i)) } fn tag() -> &'static str { - "RegionVid" + "RegionVidKey" + } +} + +impl<'tcx> UnifyValue for UnifiedRegion<'tcx> { + type Error = NoError; + + fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> { + Ok(match (value1.0, value2.0) { + // Here we can just pick one value, because the full constraints graph + // will be handled later. Ideally, we might want a `MultipleValues` + // variant or something. For now though, this is fine. + (Some(_), Some(_)) => *value1, + + (Some(_), _) => *value1, + (_, Some(_)) => *value2, + + (None, None) => *value1, + }) } } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 597a4fd0f52..e1d7bc4be53 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -29,14 +29,12 @@ #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(const_panic)] #![feature(core_intrinsics)] #![feature(discriminant_kind)] #![feature(never_type)] #![feature(extern_types)] #![feature(nll)] #![feature(once_cell)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(min_specialization)] #![feature(trusted_len)] #![feature(test)] @@ -83,6 +81,7 @@ pub mod infer; pub mod lint; pub mod middle; pub mod mir; +pub mod thir; pub mod traits; pub mod ty; diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs index 38d0793a682..4c7ea937ceb 100644 --- a/compiler/rustc_middle/src/lint.rs +++ b/compiler/rustc_middle/src/lint.rs @@ -1,7 +1,7 @@ use std::cmp; use crate::ich::StableHashingContext; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_errors::{DiagnosticBuilder, DiagnosticId}; use rustc_hir::HirId; @@ -28,6 +28,9 @@ pub enum LintLevelSource { /// The provided `Level` is the level specified on the command line. /// (The actual level may be lower due to `--cap-lints`.) CommandLine(Symbol, Level), + + /// Lint is being forced to warn no matter what. + ForceWarn(Symbol), } impl LintLevelSource { @@ -36,6 +39,7 @@ impl LintLevelSource { LintLevelSource::Default => symbol::kw::Default, LintLevelSource::Node(name, _, _) => name, LintLevelSource::CommandLine(name, _) => name, + LintLevelSource::ForceWarn(name) => name, } } @@ -44,6 +48,7 @@ impl LintLevelSource { LintLevelSource::Default => DUMMY_SP, LintLevelSource::Node(_, span, _) => span, LintLevelSource::CommandLine(_, _) => DUMMY_SP, + LintLevelSource::ForceWarn(_) => DUMMY_SP, } } } @@ -55,6 +60,7 @@ pub type LevelAndSource = (Level, LintLevelSource); pub struct LintLevelSets { pub list: Vec<LintSet>, pub lint_cap: Level, + pub force_warns: FxHashSet<LintId>, } #[derive(Debug)] @@ -73,7 +79,11 @@ pub enum LintSet { impl LintLevelSets { pub fn new() -> Self { - LintLevelSets { list: Vec::new(), lint_cap: Level::Forbid } + LintLevelSets { + list: Vec::new(), + lint_cap: Level::Forbid, + force_warns: FxHashSet::default(), + } } pub fn get_lint_level( @@ -83,6 +93,11 @@ impl LintLevelSets { aux: Option<&FxHashMap<LintId, LevelAndSource>>, sess: &Session, ) -> LevelAndSource { + // Check whether we should always warn + if self.force_warns.contains(&LintId::of(lint)) { + return (Level::Warn, LintLevelSource::ForceWarn(Symbol::intern(lint.name))); + } + let (level, mut src) = self.get_lint_id_level(LintId::of(lint), idx, aux); // If `level` is none then we actually assume the default level for this @@ -176,11 +191,11 @@ impl LintLevelMap { impl<'a> HashStable<StableHashingContext<'a>> for LintLevelMap { #[inline] fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { - let LintLevelMap { ref sets, ref id_to_set } = *self; + let LintLevelMap { ref sets, ref id_to_set, .. } = *self; id_to_set.hash_stable(hcx, hasher); - let LintLevelSets { ref list, lint_cap } = *sets; + let LintLevelSets { ref list, lint_cap, .. } = *sets; lint_cap.hash_stable(hcx, hasher); @@ -346,6 +361,13 @@ pub fn struct_lint_level<'s, 'd>( ); } } + LintLevelSource::ForceWarn(_) => { + sess.diag_note_once( + &mut err, + DiagnosticMessageId::from(lint), + "warning forced by `force-warns` commandline option", + ); + } } err.code(DiagnosticId::Lint { name, has_future_breakage }); diff --git a/compiler/rustc_middle/src/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs index d63116e29c8..dd3b0a40d69 100644 --- a/compiler/rustc_middle/src/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -14,7 +14,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathHash}; use rustc_macros::HashStable; use rustc_session::search_paths::PathKind; use rustc_session::utils::NativeLibKind; -use rustc_session::CrateDisambiguator; +use rustc_session::StableCrateId; use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_target::spec::Target; @@ -199,8 +199,7 @@ pub trait CrateStore { // "queries" used in resolve that aren't tracked for incremental compilation fn crate_name_untracked(&self, cnum: CrateNum) -> Symbol; - fn crate_is_private_dep_untracked(&self, cnum: CrateNum) -> bool; - fn crate_disambiguator_untracked(&self, cnum: CrateNum) -> CrateDisambiguator; + fn stable_crate_id_untracked(&self, cnum: CrateNum) -> StableCrateId; fn crate_hash_untracked(&self, cnum: CrateNum) -> Svh; // This is basically a 1-based range of ints, which is a little diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs index 276e45ce99b..5ea78e087f8 100644 --- a/compiler/rustc_middle/src/middle/exported_symbols.rs +++ b/compiler/rustc_middle/src/middle/exported_symbols.rs @@ -48,8 +48,8 @@ impl<'tcx> ExportedSymbol<'tcx> { pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String { format!( - "rust_metadata_{}_{}", - tcx.original_crate_name(LOCAL_CRATE), - tcx.crate_disambiguator(LOCAL_CRATE).to_fingerprint().to_hex() + "rust_metadata_{}_{:08x}", + tcx.crate_name(LOCAL_CRATE), + tcx.sess.local_stable_crate_id().to_u64(), ) } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 929818bd1ee..ee3902991e9 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -4,16 +4,22 @@ use std::borrow::Cow; use std::convert::TryFrom; use std::iter; use std::ops::{Deref, DerefMut, Range}; +use std::ptr; use rustc_ast::Mutability; use rustc_data_structures::sorted_map::SortedMap; use rustc_target::abi::{Align, HasDataLayout, Size}; use super::{ - read_target_uint, write_target_uint, AllocId, InterpResult, Pointer, Scalar, ScalarMaybeUninit, - UninitBytesAccess, + read_target_uint, write_target_uint, AllocId, InterpError, Pointer, Scalar, ScalarMaybeUninit, + UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, }; +/// This type represents an Allocation in the Miri/CTFE core engine. +/// +/// Its public API is rather low-level, working directly with allocation offsets and a custom error +/// type to account for the lack of an AllocId on this level. The Miri/CTFE core engine `memory` +/// module provides higher-level access. #[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)] #[derive(HashStable)] pub struct Allocation<Tag = (), Extra = ()> { @@ -38,54 +44,67 @@ pub struct Allocation<Tag = (), Extra = ()> { pub extra: Extra, } -pub trait AllocationExtra<Tag>: std::fmt::Debug + Clone { - // There is no constructor in here because the constructor's type depends - // on `MemoryKind`, and making things sufficiently generic leads to painful - // inference failure. +/// We have our own error type that does not know about the `AllocId`; that information +/// is added when converting to `InterpError`. +#[derive(Debug)] +pub enum AllocError { + /// Encountered a pointer where we needed raw bytes. + ReadPointerAsBytes, + /// Using uninitialized data where it is not allowed. + InvalidUninitBytes(Option<UninitBytesAccess>), +} +pub type AllocResult<T = ()> = Result<T, AllocError>; - /// Hook for performing extra checks on a memory read access. - /// - /// Takes read-only access to the allocation so we can keep all the memory read - /// operations take `&self`. Use a `RefCell` in `AllocExtra` if you - /// need to mutate. - #[inline(always)] - fn memory_read( - _alloc: &Allocation<Tag, Self>, - _ptr: Pointer<Tag>, - _size: Size, - ) -> InterpResult<'tcx> { - Ok(()) +impl AllocError { + pub fn to_interp_error<'tcx>(self, alloc_id: AllocId) -> InterpError<'tcx> { + match self { + AllocError::ReadPointerAsBytes => { + InterpError::Unsupported(UnsupportedOpInfo::ReadPointerAsBytes) + } + AllocError::InvalidUninitBytes(info) => InterpError::UndefinedBehavior( + UndefinedBehaviorInfo::InvalidUninitBytes(info.map(|b| (alloc_id, b))), + ), + } } +} + +/// The information that makes up a memory access: offset and size. +#[derive(Copy, Clone, Debug)] +pub struct AllocRange { + pub start: Size, + pub size: Size, +} + +/// Free-starting constructor for less syntactic overhead. +#[inline(always)] +pub fn alloc_range(start: Size, size: Size) -> AllocRange { + AllocRange { start, size } +} - /// Hook for performing extra checks on a memory write access. +impl AllocRange { #[inline(always)] - fn memory_written( - _alloc: &mut Allocation<Tag, Self>, - _ptr: Pointer<Tag>, - _size: Size, - ) -> InterpResult<'tcx> { - Ok(()) + pub fn end(self) -> Size { + self.start + self.size // This does overflow checking. } - /// Hook for performing extra checks on a memory deallocation. - /// `size` will be the size of the allocation. - #[inline(always)] - fn memory_deallocated( - _alloc: &mut Allocation<Tag, Self>, - _ptr: Pointer<Tag>, - _size: Size, - ) -> InterpResult<'tcx> { - Ok(()) + /// Returns the `subrange` within this range; panics if it is not a subrange. + #[inline] + pub fn subrange(self, subrange: AllocRange) -> AllocRange { + let sub_start = self.start + subrange.start; + let range = alloc_range(sub_start, subrange.size); + assert!(range.end() <= self.end(), "access outside the bounds for given AllocRange"); + range } } -// For `Tag = ()` and no extra state, we have a trivial implementation. -impl AllocationExtra<()> for () {} - // The constructors are all without extra; the extra gets added by a machine hook later. impl<Tag> Allocation<Tag> { - /// Creates a read-only allocation initialized by the given bytes - pub fn from_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>, align: Align) -> Self { + /// Creates an allocation initialized by the given bytes + pub fn from_bytes<'a>( + slice: impl Into<Cow<'a, [u8]>>, + align: Align, + mutability: Mutability, + ) -> Self { let bytes = slice.into().into_owned(); let size = Size::from_bytes(bytes.len()); Self { @@ -93,13 +112,13 @@ impl<Tag> Allocation<Tag> { relocations: Relocations::new(), init_mask: InitMask::new(size, true), align, - mutability: Mutability::Not, + mutability, extra: (), } } - pub fn from_byte_aligned_bytes<'a>(slice: impl Into<Cow<'a, [u8]>>) -> Self { - Allocation::from_bytes(slice, Align::from_bytes(1).unwrap()) + pub fn from_bytes_byte_aligned_immutable<'a>(slice: impl Into<Cow<'a, [u8]>>) -> Self { + Allocation::from_bytes(slice, Align::ONE, Mutability::Not) } pub fn uninit(size: Size, align: Align) -> Self { @@ -114,7 +133,7 @@ impl<Tag> Allocation<Tag> { } } -impl Allocation<(), ()> { +impl Allocation<()> { /// Add Tag and Extra fields pub fn with_tags_and_extra<T, E>( self, @@ -154,7 +173,7 @@ impl<Tag, Extra> Allocation<Tag, Extra> { /// Looks at a slice which may describe uninitialized bytes or describe a relocation. This differs /// from `get_bytes_with_uninit_and_ptr` in that it does no relocation checks (even on the - /// edges) at all. It further ignores `AllocationExtra` callbacks. + /// edges) at all. /// This must not be used for reads affecting the interpreter execution. pub fn inspect_with_uninit_and_ptr_outside_interpreter(&self, range: Range<usize>) -> &[u8] { &self.bytes[range] @@ -172,23 +191,7 @@ impl<Tag, Extra> Allocation<Tag, Extra> { } /// Byte accessors. -impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { - /// Just a small local helper function to avoid a bit of code repetition. - /// Returns the range of this allocation that was meant. - #[inline] - fn check_bounds(&self, offset: Size, size: Size) -> Range<usize> { - let end = offset + size; // This does overflow checking. - let end = usize::try_from(end.bytes()).expect("access too big for this host architecture"); - assert!( - end <= self.len(), - "Out-of-bounds access at offset {}, size {} in allocation of size {}", - offset.bytes(), - size.bytes(), - self.len() - ); - offset.bytes_usize()..end - } - +impl<Tag: Copy, Extra> Allocation<Tag, Extra> { /// The last argument controls whether we error out when there are uninitialized /// or pointer bytes. You should never call this, call `get_bytes` or /// `get_bytes_with_uninit_and_ptr` instead, @@ -201,23 +204,18 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { fn get_bytes_internal( &self, cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, + range: AllocRange, check_init_and_ptr: bool, - ) -> InterpResult<'tcx, &[u8]> { - let range = self.check_bounds(ptr.offset, size); - + ) -> AllocResult<&[u8]> { if check_init_and_ptr { - self.check_init(ptr, size)?; - self.check_relocations(cx, ptr, size)?; + self.check_init(range)?; + self.check_relocations(cx, range)?; } else { // We still don't want relocations on the *edges*. - self.check_relocation_edges(cx, ptr, size)?; + self.check_relocation_edges(cx, range)?; } - AllocationExtra::memory_read(self, ptr, size)?; - - Ok(&self.bytes[range]) + Ok(&self.bytes[range.start.bytes_usize()..range.end().bytes_usize()]) } /// Checks that these bytes are initialized and not pointer bytes, and then return them @@ -227,13 +225,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods /// on `InterpCx` instead. #[inline] - pub fn get_bytes( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx, &[u8]> { - self.get_bytes_internal(cx, ptr, size, true) + pub fn get_bytes(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult<&[u8]> { + self.get_bytes_internal(cx, range, true) } /// It is the caller's responsibility to handle uninitialized and pointer bytes. @@ -244,10 +237,9 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { pub fn get_bytes_with_uninit_and_ptr( &self, cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx, &[u8]> { - self.get_bytes_internal(cx, ptr, size, false) + range: AllocRange, + ) -> AllocResult<&[u8]> { + self.get_bytes_internal(cx, range, false) } /// Just calling this already marks everything as defined and removes relocations, @@ -256,69 +248,46 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { /// It is the caller's responsibility to check bounds and alignment beforehand. /// Most likely, you want to use the `PlaceTy` and `OperandTy`-based methods /// on `InterpCx` instead. - pub fn get_bytes_mut( - &mut self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx, &mut [u8]> { - let range = self.check_bounds(ptr.offset, size); + pub fn get_bytes_mut(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> &mut [u8] { + self.mark_init(range, true); + self.clear_relocations(cx, range); - self.mark_init(ptr, size, true); - self.clear_relocations(cx, ptr, size); + &mut self.bytes[range.start.bytes_usize()..range.end().bytes_usize()] + } - AllocationExtra::memory_written(self, ptr, size)?; + /// A raw pointer variant of `get_bytes_mut` that avoids invalidating existing aliases into this memory. + pub fn get_bytes_mut_ptr(&mut self, cx: &impl HasDataLayout, range: AllocRange) -> *mut [u8] { + self.mark_init(range, true); + self.clear_relocations(cx, range); - Ok(&mut self.bytes[range]) + assert!(range.end().bytes_usize() <= self.bytes.len()); // need to do our own bounds-check + let begin_ptr = self.bytes.as_mut_ptr().wrapping_add(range.start.bytes_usize()); + let len = range.end().bytes_usize() - range.start.bytes_usize(); + ptr::slice_from_raw_parts_mut(begin_ptr, len) } } /// Reading and writing. -impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { +impl<Tag: Copy, Extra> Allocation<Tag, Extra> { /// Validates that `ptr.offset` and `ptr.offset + size` do not point to the middle of a /// relocation. If `allow_uninit_and_ptr` is `false`, also enforces that the memory in the /// given range contains neither relocations nor uninitialized bytes. pub fn check_bytes( &self, cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, + range: AllocRange, allow_uninit_and_ptr: bool, - ) -> InterpResult<'tcx> { + ) -> AllocResult { // Check bounds and relocations on the edges. - self.get_bytes_with_uninit_and_ptr(cx, ptr, size)?; + self.get_bytes_with_uninit_and_ptr(cx, range)?; // Check uninit and ptr. if !allow_uninit_and_ptr { - self.check_init(ptr, size)?; - self.check_relocations(cx, ptr, size)?; + self.check_init(range)?; + self.check_relocations(cx, range)?; } Ok(()) } - /// Writes `src` to the memory starting at `ptr.offset`. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - /// Most likely, you want to call `Memory::write_bytes` instead of this method. - pub fn write_bytes( - &mut self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - src: impl IntoIterator<Item = u8>, - ) -> InterpResult<'tcx> { - let mut src = src.into_iter(); - let (lower, upper) = src.size_hint(); - let len = upper.expect("can only write bounded iterators"); - assert_eq!(lower, len, "can only write iterators with a precise length"); - let bytes = self.get_bytes_mut(cx, ptr, Size::from_bytes(len))?; - // `zip` would stop when the first iterator ends; we want to definitely - // cover all of `bytes`. - for dest in bytes { - *dest = src.next().expect("iterator was shorter than it said it would be"); - } - assert_matches!(src.next(), None, "iterator was longer than it said it would be"); - Ok(()) - } - /// Reads a *non-ZST* scalar. /// /// ZSTs can't be read because in order to obtain a `Pointer`, we need to check @@ -329,14 +298,13 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { pub fn read_scalar( &self, cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { + range: AllocRange, + ) -> AllocResult<ScalarMaybeUninit<Tag>> { // `get_bytes_unchecked` tests relocation edges. - let bytes = self.get_bytes_with_uninit_and_ptr(cx, ptr, size)?; + let bytes = self.get_bytes_with_uninit_and_ptr(cx, range)?; // Uninit check happens *after* we established that the alignment is correct. // We must not return `Ok()` for unaligned pointers! - if self.is_init(ptr, size).is_err() { + if self.is_init(range).is_err() { // This inflates uninitialized bytes to the entire scalar, even if only a few // bytes are uninitialized. return Ok(ScalarMaybeUninit::Uninit); @@ -344,29 +312,19 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { // Now we do the actual reading. let bits = read_target_uint(cx.data_layout().endian, bytes).unwrap(); // See if we got a pointer. - if size != cx.data_layout().pointer_size { + if range.size != cx.data_layout().pointer_size { + // Not a pointer. // *Now*, we better make sure that the inside is free of relocations too. - self.check_relocations(cx, ptr, size)?; + self.check_relocations(cx, range)?; } else { - if let Some(&(tag, alloc_id)) = self.relocations.get(&ptr.offset) { + // Maybe a pointer. + if let Some(&(tag, alloc_id)) = self.relocations.get(&range.start) { let ptr = Pointer::new_with_tag(alloc_id, Size::from_bytes(bits), tag); return Ok(ScalarMaybeUninit::Scalar(ptr.into())); } } // We don't. Just return the bits. - Ok(ScalarMaybeUninit::Scalar(Scalar::from_uint(bits, size))) - } - - /// Reads a pointer-sized scalar. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - /// Most likely, you want to call `InterpCx::read_scalar` instead of this method. - pub fn read_ptr_sized( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - ) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { - self.read_scalar(cx, ptr, cx.data_layout().pointer_size) + Ok(ScalarMaybeUninit::Scalar(Scalar::from_uint(bits, range.size))) } /// Writes a *non-ZST* scalar. @@ -379,78 +337,56 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra<Tag>> Allocation<Tag, Extra> { pub fn write_scalar( &mut self, cx: &impl HasDataLayout, - ptr: Pointer<Tag>, + range: AllocRange, val: ScalarMaybeUninit<Tag>, - type_size: Size, - ) -> InterpResult<'tcx> { + ) -> AllocResult { let val = match val { ScalarMaybeUninit::Scalar(scalar) => scalar, ScalarMaybeUninit::Uninit => { - self.mark_init(ptr, type_size, false); + self.mark_init(range, false); return Ok(()); } }; - let bytes = match val.to_bits_or_ptr(type_size, cx) { + let bytes = match val.to_bits_or_ptr(range.size, cx) { Err(val) => u128::from(val.offset.bytes()), Ok(data) => data, }; let endian = cx.data_layout().endian; - let dst = self.get_bytes_mut(cx, ptr, type_size)?; + let dst = self.get_bytes_mut(cx, range); write_target_uint(endian, dst, bytes).unwrap(); // See if we have to also write a relocation. if let Scalar::Ptr(val) = val { - self.relocations.insert(ptr.offset, (val.tag, val.alloc_id)); + self.relocations.insert(range.start, (val.tag, val.alloc_id)); } Ok(()) } - - /// Writes a pointer-sized scalar. - /// - /// It is the caller's responsibility to check bounds and alignment beforehand. - /// Most likely, you want to call `InterpCx::write_scalar` instead of this method. - pub fn write_ptr_sized( - &mut self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - val: ScalarMaybeUninit<Tag>, - ) -> InterpResult<'tcx> { - let ptr_size = cx.data_layout().pointer_size; - self.write_scalar(cx, ptr, val, ptr_size) - } } /// Relocations. -impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> { +impl<Tag: Copy, Extra> Allocation<Tag, Extra> { /// Returns all relocations overlapping with the given pointer-offset pair. pub fn get_relocations( &self, cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, + range: AllocRange, ) -> &[(Size, (Tag, AllocId))] { // We have to go back `pointer_size - 1` bytes, as that one would still overlap with // the beginning of this range. - let start = ptr.offset.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1); - let end = ptr.offset + size; // This does overflow checking. - self.relocations.range(Size::from_bytes(start)..end) + let start = range.start.bytes().saturating_sub(cx.data_layout().pointer_size.bytes() - 1); + self.relocations.range(Size::from_bytes(start)..range.end()) } /// Checks that there are no relocations overlapping with the given range. #[inline(always)] - fn check_relocations( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx> { - if self.get_relocations(cx, ptr, size).is_empty() { + fn check_relocations(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult { + if self.get_relocations(cx, range).is_empty() { Ok(()) } else { - throw_unsup!(ReadPointerAsBytes) + Err(AllocError::ReadPointerAsBytes) } } @@ -460,11 +396,11 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> { /// uninitialized. This is a somewhat odd "spooky action at a distance", /// but it allows strictly more code to run than if we would just error /// immediately in that case. - fn clear_relocations(&mut self, cx: &impl HasDataLayout, ptr: Pointer<Tag>, size: Size) { + fn clear_relocations(&mut self, cx: &impl HasDataLayout, range: AllocRange) { // Find the start and end of the given range and its outermost relocations. let (first, last) = { // Find all relocations overlapping the given range. - let relocations = self.get_relocations(cx, ptr, size); + let relocations = self.get_relocations(cx, range); if relocations.is_empty() { return; } @@ -474,8 +410,8 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> { relocations.last().unwrap().0 + cx.data_layout().pointer_size, ) }; - let start = ptr.offset; - let end = start + size; // `Size` addition + let start = range.start; + let end = range.end(); // Mark parts of the outermost relocations as uninitialized if they partially fall outside the // given range. @@ -493,46 +429,41 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> { /// Errors if there are relocations overlapping with the edges of the /// given memory range. #[inline] - fn check_relocation_edges( - &self, - cx: &impl HasDataLayout, - ptr: Pointer<Tag>, - size: Size, - ) -> InterpResult<'tcx> { - self.check_relocations(cx, ptr, Size::ZERO)?; - self.check_relocations(cx, ptr.offset(size, cx)?, Size::ZERO)?; + fn check_relocation_edges(&self, cx: &impl HasDataLayout, range: AllocRange) -> AllocResult { + self.check_relocations(cx, alloc_range(range.start, Size::ZERO))?; + self.check_relocations(cx, alloc_range(range.end(), Size::ZERO))?; Ok(()) } } /// Uninitialized bytes. -impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> { +impl<Tag: Copy, Extra> Allocation<Tag, Extra> { /// Checks whether the given range is entirely initialized. /// /// Returns `Ok(())` if it's initialized. Otherwise returns the range of byte /// indexes of the first contiguous uninitialized access. - fn is_init(&self, ptr: Pointer<Tag>, size: Size) -> Result<(), Range<Size>> { - self.init_mask.is_range_initialized(ptr.offset, ptr.offset + size) // `Size` addition + fn is_init(&self, range: AllocRange) -> Result<(), Range<Size>> { + self.init_mask.is_range_initialized(range.start, range.end()) // `Size` addition } /// Checks that a range of bytes is initialized. If not, returns the `InvalidUninitBytes` /// error which will report the first range of bytes which is uninitialized. - fn check_init(&self, ptr: Pointer<Tag>, size: Size) -> InterpResult<'tcx> { - self.is_init(ptr, size).or_else(|idx_range| { - throw_ub!(InvalidUninitBytes(Some(UninitBytesAccess { - access_ptr: ptr.erase_tag(), - access_size: size, - uninit_ptr: Pointer::new(ptr.alloc_id, idx_range.start), + fn check_init(&self, range: AllocRange) -> AllocResult { + self.is_init(range).or_else(|idx_range| { + Err(AllocError::InvalidUninitBytes(Some(UninitBytesAccess { + access_offset: range.start, + access_size: range.size, + uninit_offset: idx_range.start, uninit_size: idx_range.end - idx_range.start, // `Size` subtraction }))) }) } - pub fn mark_init(&mut self, ptr: Pointer<Tag>, size: Size, is_init: bool) { - if size.bytes() == 0 { + pub fn mark_init(&mut self, range: AllocRange, is_init: bool) { + if range.size.bytes() == 0 { return; } - self.init_mask.set_range(ptr.offset, ptr.offset + size, is_init); + self.init_mask.set_range(range.start, range.end(), is_init); } } @@ -667,25 +598,25 @@ impl<Tag: Copy, Extra> Allocation<Tag, Extra> { pub fn prepare_relocation_copy( &self, cx: &impl HasDataLayout, - src: Pointer<Tag>, - size: Size, - dest: Pointer<Tag>, - length: u64, + src: AllocRange, + dest: Size, + count: u64, ) -> AllocationRelocations<Tag> { - let relocations = self.get_relocations(cx, src, size); + let relocations = self.get_relocations(cx, src); if relocations.is_empty() { return AllocationRelocations { relative_relocations: Vec::new() }; } - let mut new_relocations = Vec::with_capacity(relocations.len() * (length as usize)); + let size = src.size; + let mut new_relocations = Vec::with_capacity(relocations.len() * (count as usize)); - for i in 0..length { + for i in 0..count { new_relocations.extend(relocations.iter().map(|&(offset, reloc)| { // compute offset for current repetition - let dest_offset = dest.offset + size * i; // `Size` operations + let dest_offset = dest + size * i; // `Size` operations ( // shift offsets from source allocation to destination allocation - (offset + dest_offset) - src.offset, // `Size` operations + (offset + dest_offset) - src.start, // `Size` operations reloc, ) })); diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index 9c3bed6ec0a..65d9c1dd90e 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -198,11 +198,11 @@ impl fmt::Display for CheckInAllocMsg { #[derive(Debug)] pub struct UninitBytesAccess { /// Location of the original memory access. - pub access_ptr: Pointer, + pub access_offset: Size, /// Size of the original memory access. pub access_size: Size, /// Location of the first uninitialized byte that was accessed. - pub uninit_ptr: Pointer, + pub uninit_offset: Size, /// Number of consecutive uninitialized bytes that were accessed. pub uninit_size: Size, } @@ -264,7 +264,7 @@ pub enum UndefinedBehaviorInfo<'tcx> { /// Using a string that is not valid UTF-8, InvalidStr(std::str::Utf8Error), /// Using uninitialized data where it is not allowed. - InvalidUninitBytes(Option<UninitBytesAccess>), + InvalidUninitBytes(Option<(AllocId, UninitBytesAccess)>), /// Working with a local that is not currently live. DeadLocal, /// Data size is not equal to target size. @@ -335,18 +335,18 @@ impl fmt::Display for UndefinedBehaviorInfo<'_> { write!(f, "using {} as function pointer but it does not point to a function", p) } InvalidStr(err) => write!(f, "this string is not valid UTF-8: {}", err), - InvalidUninitBytes(Some(access)) => write!( + InvalidUninitBytes(Some((alloc, access))) => write!( f, "reading {} byte{} of memory starting at {}, \ but {} byte{} {} uninitialized starting at {}, \ and this operation requires initialized memory", access.access_size.bytes(), pluralize!(access.access_size.bytes()), - access.access_ptr, + Pointer::new(*alloc, access.access_offset), access.uninit_size.bytes(), pluralize!(access.uninit_size.bytes()), if access.uninit_size.bytes() != 1 { "are" } else { "is" }, - access.uninit_ptr, + Pointer::new(*alloc, access.uninit_offset), ), InvalidUninitBytes(None) => write!( f, @@ -435,8 +435,12 @@ impl<T: Any> AsAny for T { } /// A trait for machine-specific errors (or other "machine stop" conditions). -pub trait MachineStopType: AsAny + fmt::Display + Send {} -impl MachineStopType for String {} +pub trait MachineStopType: AsAny + fmt::Display + Send { + /// If `true`, emit a hard error instead of going through the `CONST_ERR` lint + fn is_hard_err(&self) -> bool { + false + } +} impl dyn MachineStopType { #[inline(always)] @@ -446,7 +450,7 @@ impl dyn MachineStopType { } #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(InterpError<'_>, 72); +static_assert_size!(InterpError<'_>, 64); pub enum InterpError<'tcx> { /// The program caused undefined behavior. diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index 55fe5f971e7..14bdb0a5a2d 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -125,7 +125,7 @@ pub use self::error::{ pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit}; -pub use self::allocation::{Allocation, AllocationExtra, InitMask, Relocations}; +pub use self::allocation::{alloc_range, AllocRange, Allocation, InitMask, Relocations}; pub use self::pointer::{Pointer, PointerArithmetic}; @@ -246,6 +246,7 @@ pub struct AllocDecodingState { } impl AllocDecodingState { + #[inline] pub fn new_decoding_session(&self) -> AllocDecodingSession<'_> { static DECODER_SESSION_ID: AtomicU32 = AtomicU32::new(0); let counter = DECODER_SESSION_ID.fetch_add(1, Ordering::SeqCst); diff --git a/compiler/rustc_middle/src/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs index 888777a9418..66ff6990e8c 100644 --- a/compiler/rustc_middle/src/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -10,7 +10,7 @@ use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; use crate::ty::{Lift, ParamEnv, ScalarInt, Ty, TyCtxt}; -use super::{AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; +use super::{AllocId, AllocRange, Allocation, InterpResult, Pointer, PointerArithmetic}; /// Represents the result of const evaluation via the `eval_to_allocation` query. #[derive(Copy, Clone, HashStable, TyEncodable, TyDecodable, Debug, Hash, Eq, PartialEq)] @@ -661,9 +661,7 @@ pub fn get_slice_bytes<'tcx>(cx: &impl HasDataLayout, val: ConstValue<'tcx>) -> let len = end - start; data.get_bytes( cx, - // invent a pointer, only the offset is relevant anyway - Pointer::new(AllocId(0), Size::from_bytes(start)), - Size::from_bytes(len), + AllocRange { start: Size::from_bytes(start), size: Size::from_bytes(len) }, ) .unwrap_or_else(|err| bug!("const slice is invalid: {:?}", err)) } else { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 1cc7f235d7d..7ae7eab6e5a 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1249,10 +1249,12 @@ impl<'tcx> BasicBlockData<'tcx> { /// /// Terminator may not be None after construction of the basic block is complete. This accessor /// provides a convenience way to reach the terminator. + #[inline] pub fn terminator(&self) -> &Terminator<'tcx> { self.terminator.as_ref().expect("invalid terminator state") } + #[inline] pub fn terminator_mut(&mut self) -> &mut Terminator<'tcx> { self.terminator.as_mut().expect("invalid terminator state") } @@ -1870,6 +1872,7 @@ impl<'tcx> PlaceRef<'tcx> { /// If this place represents a local variable like `_X` with no /// projections, return `Some(_X)`. + #[inline] pub fn as_local(&self) -> Option<Local> { match *self { PlaceRef { local, projection: [] } => Some(local), @@ -1877,6 +1880,7 @@ impl<'tcx> PlaceRef<'tcx> { } } + #[inline] pub fn last_projection(&self) -> Option<(PlaceRef<'tcx>, PlaceElem<'tcx>)> { if let &[ref proj_base @ .., elem] = self.projection { Some((PlaceRef { local: self.local, projection: proj_base }, elem)) @@ -2464,12 +2468,14 @@ impl Constant<'tcx> { _ => None, } } + #[inline] pub fn ty(&self) -> Ty<'tcx> { self.literal.ty() } } impl From<&'tcx ty::Const<'tcx>> for ConstantKind<'tcx> { + #[inline] fn from(ct: &'tcx ty::Const<'tcx>) -> Self { Self::Ty(ct) } diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index edf2e539765..c354cdd985b 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -186,6 +186,15 @@ impl<'tcx> MonoItem<'tcx> { pub fn codegen_dep_node(&self, tcx: TyCtxt<'tcx>) -> DepNode { crate::dep_graph::make_compile_mono_item(tcx, self) } + + /// Returns the item's `CrateNum` + pub fn krate(&self) -> CrateNum { + match self { + MonoItem::Fn(ref instance) => instance.def_id().krate, + MonoItem::Static(def_id) => def_id.krate, + MonoItem::GlobalAsm(..) => LOCAL_CRATE, + } + } } impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for MonoItem<'tcx> { @@ -258,6 +267,7 @@ pub enum Visibility { } impl<'tcx> CodegenUnit<'tcx> { + #[inline] pub fn new(name: Symbol) -> CodegenUnit<'tcx> { CodegenUnit { name, items: Default::default(), size_estimate: None, primary: false } } @@ -302,6 +312,7 @@ impl<'tcx> CodegenUnit<'tcx> { self.size_estimate = Some(self.items.keys().map(|mi| mi.size_estimate(tcx)).sum()); } + #[inline] pub fn size_estimate(&self) -> usize { // Should only be called if `estimate_size` has previously been called. self.size_estimate.expect("estimate_size must be called before getting a size_estimate") @@ -479,15 +490,18 @@ impl CodegenUnitNameBuilder<'tcx> { // local crate's ID. Otherwise there can be collisions between CGUs // instantiating stuff for upstream crates. let local_crate_id = if cnum != LOCAL_CRATE { - let local_crate_disambiguator = format!("{}", tcx.crate_disambiguator(LOCAL_CRATE)); - format!("-in-{}.{}", tcx.crate_name(LOCAL_CRATE), &local_crate_disambiguator[0..8]) + let local_stable_crate_id = tcx.sess.local_stable_crate_id(); + format!( + "-in-{}.{:08x}", + tcx.crate_name(LOCAL_CRATE), + local_stable_crate_id.to_u64() + ) } else { String::new() }; - let crate_disambiguator = tcx.crate_disambiguator(cnum).to_string(); - // Using a shortened disambiguator of about 40 bits - format!("{}.{}{}", tcx.crate_name(cnum), &crate_disambiguator[0..8], local_crate_id) + let stable_crate_id = tcx.sess.local_stable_crate_id(); + format!("{}.{:08x}{}", tcx.crate_name(cnum), stable_crate_id.to_u64(), local_crate_id) }); write!(cgu_name, "{}", crate_prefix).unwrap(); diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index a80aa6ad3d8..0edb79fdbc8 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -32,7 +32,6 @@ pub enum UnsafetyViolationDetails { UseOfInlineAssembly, InitializingTypeWith, CastOfPointerToInt, - BorrowOfPackedField, UseOfMutableStatic, UseOfExternStatic, DerefOfRawPointer, @@ -64,11 +63,6 @@ impl UnsafetyViolationDetails { CastOfPointerToInt => { ("cast of pointer to int", "casting pointers to integers in constants") } - BorrowOfPackedField => ( - "borrow of packed field", - "fields of packed structs might be misaligned: dereferencing a misaligned pointer \ - or even just creating a misaligned reference is undefined behavior", - ), UseOfMutableStatic => ( "use of mutable static", "mutable statics can be mutated by multiple threads: aliasing violations or data \ diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 70f70788bca..f65dfea04eb 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -47,7 +47,7 @@ rustc_queries! { /// /// This can be conveniently accessed by methods on `tcx.hir()`. /// Avoid calling this query directly. - query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> { + query hir_owner(key: LocalDefId) -> Option<crate::hir::Owner<'tcx>> { eval_always desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } } @@ -220,6 +220,13 @@ rustc_queries! { desc { "checking if the crate is_panic_runtime" } } + /// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`. + query thir_body(key: ty::WithOptConstParam<LocalDefId>) -> (&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId) { + // Perf tests revealed that hashing THIR is inefficient (see #85729). + no_hash + desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key.did.to_def_id()) } + } + /// Set of all the `DefId`s in this crate that have MIR associated with /// them. This includes all the body owners, but also things like struct /// constructors. @@ -1120,8 +1127,7 @@ rustc_queries! { desc { "computing whether impls specialize one another" } } query in_scope_traits_map(_: LocalDefId) - -> Option<&'tcx FxHashMap<ItemLocalId, StableVec<TraitCandidate>>> { - eval_always + -> Option<&'tcx FxHashMap<ItemLocalId, Box<[TraitCandidate]>>> { desc { "traits in scope at a block" } } @@ -1231,10 +1237,6 @@ rustc_queries! { query proc_macro_decls_static(_: ()) -> Option<LocalDefId> { desc { "looking up the derive registrar for a crate" } } - query crate_disambiguator(_: CrateNum) -> CrateDisambiguator { - eval_always - desc { "looking up the disambiguator a crate" } - } // The macro which defines `rustc_metadata::provide_extern` depends on this query's name. // Changing the name should cause a compiler error, but in case that changes, be aware. query crate_hash(_: CrateNum) -> Svh { @@ -1245,10 +1247,6 @@ rustc_queries! { eval_always desc { "looking up the hash of a host version of a crate" } } - query original_crate_name(_: CrateNum) -> Symbol { - eval_always - desc { "looking up the original name a crate" } - } query extra_filename(_: CrateNum) -> String { eval_always desc { "looking up the extra filename for a crate" } @@ -1412,6 +1410,12 @@ rustc_queries! { eval_always desc { "generating a postorder list of CrateNums" } } + /// Returns whether or not the crate with CrateNum 'cnum' + /// is marked as a private dependency + query is_private_dep(c: CrateNum) -> bool { + eval_always + desc { "check whether crate {} is a private dependency", c } + } query upvars_mentioned(def_id: DefId) -> Option<&'tcx FxIndexMap<hir::HirId, hir::Upvar>> { desc { |tcx| "collecting upvars mentioned in `{}`", tcx.def_path_str(def_id) } diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs new file mode 100644 index 00000000000..a5069113702 --- /dev/null +++ b/compiler/rustc_middle/src/thir.rs @@ -0,0 +1,747 @@ +use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; +use rustc_hir as hir; +use rustc_hir::def::CtorKind; +use rustc_hir::def_id::DefId; +use rustc_hir::RangeEnd; +use rustc_index::newtype_index; +use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::infer::canonical::Canonical; +use rustc_middle::middle::region; +use rustc_middle::mir::{ + BinOp, BorrowKind, FakeReadCause, Field, Mutability, UnOp, UserTypeProjection, +}; +use rustc_middle::ty::adjustment::PointerCast; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{self, AdtDef, Const, Ty, UpvarSubsts, UserType}; +use rustc_middle::ty::{ + CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, +}; +use rustc_span::{Span, Symbol, DUMMY_SP}; +use rustc_target::abi::VariantIdx; +use rustc_target::asm::InlineAsmRegOrRegClass; + +use std::fmt; +use std::ops::Index; + +newtype_index! { + #[derive(HashStable)] + pub struct ArmId { + DEBUG_FORMAT = "a{}" + } +} + +newtype_index! { + #[derive(HashStable)] + pub struct ExprId { + DEBUG_FORMAT = "e{}" + } +} + +newtype_index! { + #[derive(HashStable)] + pub struct StmtId { + DEBUG_FORMAT = "s{}" + } +} + +macro_rules! thir_with_elements { + ($($name:ident: $id:ty => $value:ty,)*) => { + #[derive(Debug, HashStable)] + pub struct Thir<'tcx> { + $( + pub $name: IndexVec<$id, $value>, + )* + } + + impl<'tcx> Thir<'tcx> { + pub fn new() -> Thir<'tcx> { + Thir { + $( + $name: IndexVec::new(), + )* + } + } + } + + $( + impl<'tcx> Index<$id> for Thir<'tcx> { + type Output = $value; + fn index(&self, index: $id) -> &Self::Output { + &self.$name[index] + } + } + )* + } +} + +thir_with_elements! { + arms: ArmId => Arm<'tcx>, + exprs: ExprId => Expr<'tcx>, + stmts: StmtId => Stmt<'tcx>, +} + +#[derive(Copy, Clone, Debug, HashStable)] +pub enum LintLevel { + Inherited, + Explicit(hir::HirId), +} + +#[derive(Debug, HashStable)] +pub struct Block { + pub targeted_by_break: bool, + pub region_scope: region::Scope, + pub opt_destruction_scope: Option<region::Scope>, + pub span: Span, + pub stmts: Box<[StmtId]>, + pub expr: Option<ExprId>, + pub safety_mode: BlockSafety, +} + +#[derive(Copy, Clone, Debug, HashStable)] +pub enum BlockSafety { + Safe, + ExplicitUnsafe(hir::HirId), + PushUnsafe, + PopUnsafe, +} + +#[derive(Debug, HashStable)] +pub struct Stmt<'tcx> { + pub kind: StmtKind<'tcx>, + pub opt_destruction_scope: Option<region::Scope>, +} + +#[derive(Debug, HashStable)] +pub enum StmtKind<'tcx> { + Expr { + /// scope for this statement; may be used as lifetime of temporaries + scope: region::Scope, + + /// expression being evaluated in this statement + expr: ExprId, + }, + + Let { + /// scope for variables bound in this let; covers this and + /// remaining statements in block + remainder_scope: region::Scope, + + /// scope for the initialization itself; might be used as + /// lifetime of temporaries + init_scope: region::Scope, + + /// `let <PAT> = ...` + /// + /// if a type is included, it is added as an ascription pattern + pattern: Pat<'tcx>, + + /// let pat: ty = <INIT> ... + initializer: Option<ExprId>, + + /// the lint level for this let-statement + lint_level: LintLevel, + }, +} + +// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +rustc_data_structures::static_assert_size!(Expr<'_>, 144); + +/// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`) +/// into instances of this `Expr` enum. This lowering can be done +/// basically as lazily or as eagerly as desired: every recursive +/// reference to an expression in this enum is an `ExprId`, which +/// may in turn be another instance of this enum (boxed), or else an +/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very +/// short-lived. They are created by `Thir::to_expr`, analyzed and +/// converted into MIR, and then discarded. +/// +/// If you compare `Expr` to the full compiler AST, you will see it is +/// a good bit simpler. In fact, a number of the more straight-forward +/// MIR simplifications are already done in the impl of `Thir`. For +/// example, method calls and overloaded operators are absent: they are +/// expected to be converted into `Expr::Call` instances. +#[derive(Debug, HashStable)] +pub struct Expr<'tcx> { + /// type of this expression + pub ty: Ty<'tcx>, + + /// lifetime of this expression if it should be spilled into a + /// temporary; should be None only if in a constant context + pub temp_lifetime: Option<region::Scope>, + + /// span of the expression in the source + pub span: Span, + + /// kind of expression + pub kind: ExprKind<'tcx>, +} + +#[derive(Debug, HashStable)] +pub enum ExprKind<'tcx> { + Scope { + region_scope: region::Scope, + lint_level: LintLevel, + value: ExprId, + }, + Box { + value: ExprId, + }, + If { + cond: ExprId, + then: ExprId, + else_opt: Option<ExprId>, + }, + Call { + ty: Ty<'tcx>, + fun: ExprId, + args: Box<[ExprId]>, + /// Whether this is from a call in HIR, rather than from an overloaded + /// operator. `true` for overloaded function call. + from_hir_call: bool, + /// This `Span` is the span of the function, without the dot and receiver + /// (e.g. `foo(a, b)` in `x.foo(a, b)` + fn_span: Span, + }, + Deref { + arg: ExprId, + }, // NOT overloaded! + Binary { + op: BinOp, + lhs: ExprId, + rhs: ExprId, + }, // NOT overloaded! + LogicalOp { + op: LogicalOp, + lhs: ExprId, + rhs: ExprId, + }, // NOT overloaded! + // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands. + Unary { + op: UnOp, + arg: ExprId, + }, // NOT overloaded! + Cast { + source: ExprId, + }, + Use { + source: ExprId, + }, // Use a lexpr to get a vexpr. + NeverToAny { + source: ExprId, + }, + Pointer { + cast: PointerCast, + source: ExprId, + }, + Loop { + body: ExprId, + }, + Match { + scrutinee: ExprId, + arms: Box<[ArmId]>, + }, + Block { + body: Block, + }, + Assign { + lhs: ExprId, + rhs: ExprId, + }, + AssignOp { + op: BinOp, + lhs: ExprId, + rhs: ExprId, + }, + Field { + lhs: ExprId, + name: Field, + }, + Index { + lhs: ExprId, + index: ExprId, + }, + VarRef { + id: hir::HirId, + }, + /// Used to represent upvars mentioned in a closure/generator + UpvarRef { + /// DefId of the closure/generator + closure_def_id: DefId, + + /// HirId of the root variable + var_hir_id: hir::HirId, + }, + Borrow { + borrow_kind: BorrowKind, + arg: ExprId, + }, + /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`. + AddressOf { + mutability: hir::Mutability, + arg: ExprId, + }, + Break { + label: region::Scope, + value: Option<ExprId>, + }, + Continue { + label: region::Scope, + }, + Return { + value: Option<ExprId>, + }, + ConstBlock { + value: &'tcx Const<'tcx>, + }, + Repeat { + value: ExprId, + count: &'tcx Const<'tcx>, + }, + Array { + fields: Box<[ExprId]>, + }, + Tuple { + fields: Box<[ExprId]>, + }, + Adt { + adt_def: &'tcx AdtDef, + variant_index: VariantIdx, + substs: SubstsRef<'tcx>, + + /// Optional user-given substs: for something like `let x = + /// Bar::<T> { ... }`. + user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, + + fields: Box<[FieldExpr]>, + base: Option<FruInfo<'tcx>>, + }, + PlaceTypeAscription { + source: ExprId, + /// Type that the user gave to this expression + user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, + }, + ValueTypeAscription { + source: ExprId, + /// Type that the user gave to this expression + user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, + }, + Closure { + closure_id: DefId, + substs: UpvarSubsts<'tcx>, + upvars: Box<[ExprId]>, + movability: Option<hir::Movability>, + fake_reads: Vec<(ExprId, FakeReadCause, hir::HirId)>, + }, + Literal { + literal: &'tcx Const<'tcx>, + user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, + /// The `DefId` of the `const` item this literal + /// was produced from, if this is not a user-written + /// literal value. + const_id: Option<DefId>, + }, + /// A literal containing the address of a `static`. + /// + /// This is only distinguished from `Literal` so that we can register some + /// info for diagnostics. + StaticRef { + literal: &'tcx Const<'tcx>, + def_id: DefId, + }, + InlineAsm { + template: &'tcx [InlineAsmTemplatePiece], + operands: Box<[InlineAsmOperand<'tcx>]>, + options: InlineAsmOptions, + line_spans: &'tcx [Span], + }, + /// An expression taking a reference to a thread local. + ThreadLocalRef(DefId), + LlvmInlineAsm { + asm: &'tcx hir::LlvmInlineAsmInner, + outputs: Box<[ExprId]>, + inputs: Box<[ExprId]>, + }, + Yield { + value: ExprId, + }, +} + +#[derive(Debug, HashStable)] +pub struct FieldExpr { + pub name: Field, + pub expr: ExprId, +} + +#[derive(Debug, HashStable)] +pub struct FruInfo<'tcx> { + pub base: ExprId, + pub field_types: Box<[Ty<'tcx>]>, +} + +#[derive(Debug, HashStable)] +pub struct Arm<'tcx> { + pub pattern: Pat<'tcx>, + pub guard: Option<Guard<'tcx>>, + pub body: ExprId, + pub lint_level: LintLevel, + pub scope: region::Scope, + pub span: Span, +} + +#[derive(Debug, HashStable)] +pub enum Guard<'tcx> { + If(ExprId), + IfLet(Pat<'tcx>, ExprId), +} + +#[derive(Copy, Clone, Debug, HashStable)] +pub enum LogicalOp { + And, + Or, +} + +#[derive(Debug, HashStable)] +pub enum InlineAsmOperand<'tcx> { + In { + reg: InlineAsmRegOrRegClass, + expr: ExprId, + }, + Out { + reg: InlineAsmRegOrRegClass, + late: bool, + expr: Option<ExprId>, + }, + InOut { + reg: InlineAsmRegOrRegClass, + late: bool, + expr: ExprId, + }, + SplitInOut { + reg: InlineAsmRegOrRegClass, + late: bool, + in_expr: ExprId, + out_expr: Option<ExprId>, + }, + Const { + value: &'tcx Const<'tcx>, + span: Span, + }, + SymFn { + expr: ExprId, + }, + SymStatic { + def_id: DefId, + }, +} + +#[derive(Copy, Clone, Debug, PartialEq, HashStable)] +pub enum BindingMode { + ByValue, + ByRef(BorrowKind), +} + +#[derive(Clone, Debug, PartialEq, HashStable)] +pub struct FieldPat<'tcx> { + pub field: Field, + pub pattern: Pat<'tcx>, +} + +#[derive(Clone, Debug, PartialEq, HashStable)] +pub struct Pat<'tcx> { + pub ty: Ty<'tcx>, + pub span: Span, + pub kind: Box<PatKind<'tcx>>, +} + +impl<'tcx> Pat<'tcx> { + pub fn wildcard_from_ty(ty: Ty<'tcx>) -> Self { + Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, HashStable)] +pub struct PatTyProj<'tcx> { + pub user_ty: CanonicalUserType<'tcx>, +} + +impl<'tcx> PatTyProj<'tcx> { + pub fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self { + Self { user_ty: user_annotation } + } + + pub fn user_ty( + self, + annotations: &mut CanonicalUserTypeAnnotations<'tcx>, + inferred_ty: Ty<'tcx>, + span: Span, + ) -> UserTypeProjection { + UserTypeProjection { + base: annotations.push(CanonicalUserTypeAnnotation { + span, + user_ty: self.user_ty, + inferred_ty, + }), + projs: Vec::new(), + } + } +} + +#[derive(Copy, Clone, Debug, PartialEq, HashStable)] +pub struct Ascription<'tcx> { + pub user_ty: PatTyProj<'tcx>, + /// Variance to use when relating the type `user_ty` to the **type of the value being + /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must + /// have a type that is some subtype of the ascribed type. + /// + /// Note that this variance does not apply for any bindings within subpatterns. The type + /// assigned to those bindings must be exactly equal to the `user_ty` given here. + /// + /// The only place where this field is not `Covariant` is when matching constants, where + /// we currently use `Contravariant` -- this is because the constant type just needs to + /// be "comparable" to the type of the input value. So, for example: + /// + /// ```text + /// match x { "foo" => .. } + /// ``` + /// + /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should + /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior + /// of the old type-check for now. See #57280 for details. + pub variance: ty::Variance, + pub user_ty_span: Span, +} + +#[derive(Clone, Debug, PartialEq, HashStable)] +pub enum PatKind<'tcx> { + Wild, + + AscribeUserType { + ascription: Ascription<'tcx>, + subpattern: Pat<'tcx>, + }, + + /// `x`, `ref x`, `x @ P`, etc. + Binding { + mutability: Mutability, + name: Symbol, + mode: BindingMode, + var: hir::HirId, + ty: Ty<'tcx>, + subpattern: Option<Pat<'tcx>>, + /// Is this the leftmost occurrence of the binding, i.e., is `var` the + /// `HirId` of this pattern? + is_primary: bool, + }, + + /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with + /// multiple variants. + Variant { + adt_def: &'tcx AdtDef, + substs: SubstsRef<'tcx>, + variant_index: VariantIdx, + subpatterns: Vec<FieldPat<'tcx>>, + }, + + /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with + /// a single variant. + Leaf { + subpatterns: Vec<FieldPat<'tcx>>, + }, + + /// `box P`, `&P`, `&mut P`, etc. + Deref { + subpattern: Pat<'tcx>, + }, + + /// One of the following: + /// * `&str`, which will be handled as a string pattern and thus exhaustiveness + /// checking will detect if you use the same string twice in different patterns. + /// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly + /// its own value, similar to `&str`, but these values are much simpler. + /// * Opaque constants, that must not be matched structurally. So anything that does not derive + /// `PartialEq` and `Eq`. + Constant { + value: &'tcx ty::Const<'tcx>, + }, + + Range(PatRange<'tcx>), + + /// Matches against a slice, checking the length and extracting elements. + /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. + /// e.g., `&[ref xs @ ..]`. + Slice { + prefix: Vec<Pat<'tcx>>, + slice: Option<Pat<'tcx>>, + suffix: Vec<Pat<'tcx>>, + }, + + /// Fixed match against an array; irrefutable. + Array { + prefix: Vec<Pat<'tcx>>, + slice: Option<Pat<'tcx>>, + suffix: Vec<Pat<'tcx>>, + }, + + /// An or-pattern, e.g. `p | q`. + /// Invariant: `pats.len() >= 2`. + Or { + pats: Vec<Pat<'tcx>>, + }, +} + +#[derive(Copy, Clone, Debug, PartialEq, HashStable)] +pub struct PatRange<'tcx> { + pub lo: &'tcx ty::Const<'tcx>, + pub hi: &'tcx ty::Const<'tcx>, + pub end: RangeEnd, +} + +impl<'tcx> fmt::Display for Pat<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Printing lists is a chore. + let mut first = true; + let mut start_or_continue = |s| { + if first { + first = false; + "" + } else { + s + } + }; + let mut start_or_comma = || start_or_continue(", "); + + match *self.kind { + PatKind::Wild => write!(f, "_"), + PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern), + PatKind::Binding { mutability, name, mode, ref subpattern, .. } => { + let is_mut = match mode { + BindingMode::ByValue => mutability == Mutability::Mut, + BindingMode::ByRef(bk) => { + write!(f, "ref ")?; + matches!(bk, BorrowKind::Mut { .. }) + } + }; + if is_mut { + write!(f, "mut ")?; + } + write!(f, "{}", name)?; + if let Some(ref subpattern) = *subpattern { + write!(f, " @ {}", subpattern)?; + } + Ok(()) + } + PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => { + let variant = match *self.kind { + PatKind::Variant { adt_def, variant_index, .. } => { + Some(&adt_def.variants[variant_index]) + } + _ => { + if let ty::Adt(adt, _) = self.ty.kind() { + if !adt.is_enum() { + Some(&adt.variants[VariantIdx::new(0)]) + } else { + None + } + } else { + None + } + } + }; + + if let Some(variant) = variant { + write!(f, "{}", variant.ident)?; + + // Only for Adt we can have `S {...}`, + // which we handle separately here. + if variant.ctor_kind == CtorKind::Fictive { + write!(f, " {{ ")?; + + let mut printed = 0; + for p in subpatterns { + if let PatKind::Wild = *p.pattern.kind { + continue; + } + let name = variant.fields[p.field.index()].ident; + write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?; + printed += 1; + } + + if printed < variant.fields.len() { + write!(f, "{}..", start_or_comma())?; + } + + return write!(f, " }}"); + } + } + + let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len()); + if num_fields != 0 || variant.is_none() { + write!(f, "(")?; + for i in 0..num_fields { + write!(f, "{}", start_or_comma())?; + + // Common case: the field is where we expect it. + if let Some(p) = subpatterns.get(i) { + if p.field.index() == i { + write!(f, "{}", p.pattern)?; + continue; + } + } + + // Otherwise, we have to go looking for it. + if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) { + write!(f, "{}", p.pattern)?; + } else { + write!(f, "_")?; + } + } + write!(f, ")")?; + } + + Ok(()) + } + PatKind::Deref { ref subpattern } => { + match self.ty.kind() { + ty::Adt(def, _) if def.is_box() => write!(f, "box ")?, + ty::Ref(_, _, mutbl) => { + write!(f, "&{}", mutbl.prefix_str())?; + } + _ => bug!("{} is a bad Deref pattern type", self.ty), + } + write!(f, "{}", subpattern) + } + PatKind::Constant { value } => write!(f, "{}", value), + PatKind::Range(PatRange { lo, hi, end }) => { + write!(f, "{}", lo)?; + write!(f, "{}", end)?; + write!(f, "{}", hi) + } + PatKind::Slice { ref prefix, ref slice, ref suffix } + | PatKind::Array { ref prefix, ref slice, ref suffix } => { + write!(f, "[")?; + for p in prefix { + write!(f, "{}{}", start_or_comma(), p)?; + } + if let Some(ref slice) = *slice { + write!(f, "{}", start_or_comma())?; + match *slice.kind { + PatKind::Wild => {} + _ => write!(f, "{}", slice)?, + } + write!(f, "..")?; + } + for p in suffix { + write!(f, "{}{}", start_or_comma(), p)?; + } + write!(f, "]") + } + PatKind::Or { ref pats } => { + for pat in pats { + write!(f, "{}{}", start_or_continue(" | "), pat)?; + } + Ok(()) + } + } + } +} diff --git a/compiler/rustc_middle/src/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs index a50dda69a0f..8f648b21131 100644 --- a/compiler/rustc_middle/src/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -47,7 +47,7 @@ pub enum PointerCast { /// 1. The simplest cases are where a pointer is not adjusted fat vs thin. /// Here the pointer will be dereferenced N times (where a dereference can /// happen to raw or borrowed pointers or any smart pointer which implements -/// Deref, including Box<_>). The types of dereferences is given by +/// `Deref`, including `Box<_>`). The types of dereferences is given by /// `autoderefs`. It can then be auto-referenced zero or one times, indicated /// by `autoref`, to either a raw or borrowed pointer. In these cases unsize is /// `false`. @@ -56,7 +56,7 @@ pub enum PointerCast { /// with a thin pointer, deref a number of times, unsize the underlying data, /// then autoref. The 'unsize' phase may change a fixed length array to a /// dynamically sized one, a concrete object to a trait object, or statically -/// sized struct to a dynamically sized one. E.g., &[i32; 4] -> &[i32] is +/// sized struct to a dynamically sized one. E.g., `&[i32; 4]` -> `&[i32]` is /// represented by: /// /// ``` @@ -66,7 +66,7 @@ pub enum PointerCast { /// ``` /// /// Note that for a struct, the 'deep' unsizing of the struct is not recorded. -/// E.g., `struct Foo<T> { x: T }` we can coerce &Foo<[i32; 4]> to &Foo<[i32]> +/// E.g., `struct Foo<T> { x: T }` we can coerce `&Foo<[i32; 4]>` to `&Foo<[i32]>` /// The autoderef and -ref are the same as in the above example, but the type /// stored in `unsize` is `Foo<[i32]>`, we don't store any further detail about /// the underlying conversions from `[i32; 4]` to `[i32]`. @@ -75,8 +75,8 @@ pub enum PointerCast { /// that case, we have the pointer we need coming in, so there are no /// autoderefs, and no autoref. Instead we just do the `Unsize` transformation. /// At some point, of course, `Box` should move out of the compiler, in which -/// case this is analogous to transforming a struct. E.g., Box<[i32; 4]> -> -/// Box<[i32]> is an `Adjust::Unsize` with the target `Box<[i32]>`. +/// case this is analogous to transforming a struct. E.g., `Box<[i32; 4]>` -> +/// `Box<[i32]>` is an `Adjust::Unsize` with the target `Box<[i32]>`. #[derive(Clone, TyEncodable, TyDecodable, HashStable, TypeFoldable)] pub struct Adjustment<'tcx> { pub kind: Adjust<'tcx>, diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 7790369af7f..0706a057dd0 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -1,7 +1,7 @@ use crate::hir::place::{ Place as HirPlace, PlaceBase as HirPlaceBase, ProjectionKind as HirProjectionKind, }; -use crate::ty; +use crate::{mir, ty}; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir as hir; @@ -12,6 +12,10 @@ use super::{Ty, TyCtxt}; use self::BorrowKind::*; +// Captures are represented using fields inside a structure. +// This represents accessing self in the closure structure +pub const CAPTURE_STRUCT_LOCAL: mir::Local = mir::Local::from_u32(1); + #[derive( Clone, Copy, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index dde5cbadbd9..970e669c16f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -13,6 +13,7 @@ use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath, ObjectLifetime use crate::middle::stability; use crate::mir::interpret::{self, Allocation, ConstValue, Scalar}; use crate::mir::{Body, Field, Local, Place, PlaceElem, ProjectionKind, Promoted}; +use crate::thir::Thir; use crate::traits; use crate::ty::query::{self, OnDiskCache, TyCtxtAt}; use crate::ty::subst::{GenericArg, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSubsts}; @@ -30,7 +31,7 @@ use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap}; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher, StableVec}; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; use rustc_errors::ErrorReported; @@ -965,10 +966,6 @@ pub struct GlobalCtxt<'tcx> { /// Resolutions of `extern crate` items produced by resolver. extern_crate_map: FxHashMap<LocalDefId, CrateNum>, - /// Map indicating what traits are in scope for places where this - /// is relevant; generated by resolve. - trait_map: FxHashMap<LocalDefId, FxHashMap<ItemLocalId, StableVec<TraitCandidate>>>, - /// Export map produced by name resolution. export_map: ExportMap<LocalDefId>, @@ -1008,7 +1005,7 @@ pub struct GlobalCtxt<'tcx> { /// The definite name of the current crate after taking into account /// attributes, commandline parameters, etc. - pub crate_name: Symbol, + crate_name: Symbol, /// Data layout specification for the current target. pub data_layout: TargetDataLayout, @@ -1041,6 +1038,10 @@ impl<'tcx> TyCtxt<'tcx> { } } + pub fn alloc_steal_thir(self, thir: Thir<'tcx>) -> &'tcx Steal<Thir<'tcx>> { + self.arena.alloc(Steal::new(thir)) + } + pub fn alloc_steal_mir(self, mir: Body<'tcx>) -> &'tcx Steal<Body<'tcx>> { self.arena.alloc(Steal::new(mir)) } @@ -1072,7 +1073,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Allocates a read-only byte or string literal for `mir::interpret`. pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId { // Create an allocation that just contains these bytes. - let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes); + let alloc = interpret::Allocation::from_bytes_byte_aligned_immutable(bytes); let alloc = self.intern_const_alloc(alloc); self.create_memory_alloc(alloc) } @@ -1134,7 +1135,7 @@ impl<'tcx> TyCtxt<'tcx> { on_disk_cache: Option<query::OnDiskCache<'tcx>>, queries: &'tcx dyn query::QueryEngine<'tcx>, crate_name: &str, - output_filenames: &OutputFilenames, + output_filenames: OutputFilenames, ) -> GlobalCtxt<'tcx> { let data_layout = TargetDataLayout::parse(&s.target).unwrap_or_else(|err| { s.fatal(&err); @@ -1145,12 +1146,6 @@ impl<'tcx> TyCtxt<'tcx> { let common_consts = CommonConsts::new(&interners, &common_types); let cstore = resolutions.cstore; - let mut trait_map: FxHashMap<_, FxHashMap<_, _>> = FxHashMap::default(); - for (hir_id, v) in krate.trait_map.iter() { - let map = trait_map.entry(hir_id.owner).or_default(); - map.insert(hir_id.local_id, StableVec::new(v.to_vec())); - } - GlobalCtxt { sess: s, lint_store, @@ -1164,7 +1159,6 @@ impl<'tcx> TyCtxt<'tcx> { consts: common_consts, visibilities: resolutions.visibilities, extern_crate_map: resolutions.extern_crate_map, - trait_map, export_map: resolutions.export_map, maybe_unused_trait_imports: resolutions.maybe_unused_trait_imports, maybe_unused_extern_crates: resolutions.maybe_unused_extern_crates, @@ -1185,7 +1179,7 @@ impl<'tcx> TyCtxt<'tcx> { stability_interner: Default::default(), const_stability_interner: Default::default(), alloc_map: Lock::new(interpret::AllocMap::new()), - output_filenames: Arc::new(output_filenames.clone()), + output_filenames: Arc::new(output_filenames), main_def: resolutions.main_def, } } @@ -1270,12 +1264,6 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Returns whether or not the crate with CrateNum 'cnum' - /// is marked as a private dependency - pub fn is_private_dep(self, cnum: CrateNum) -> bool { - if cnum == LOCAL_CRATE { false } else { self.cstore.crate_is_private_dep_untracked(cnum) } - } - #[inline] pub fn def_path_hash(self, def_id: DefId) -> rustc_hir::definitions::DefPathHash { if let Some(def_id) = def_id.as_local() { @@ -1287,24 +1275,24 @@ impl<'tcx> TyCtxt<'tcx> { pub fn def_path_debug_str(self, def_id: DefId) -> String { // We are explicitly not going through queries here in order to get - // crate name and disambiguator since this code is called from debug!() + // crate name and stable crate id since this code is called from debug!() // statements within the query system and we'd run into endless // recursion otherwise. - let (crate_name, crate_disambiguator) = if def_id.is_local() { - (self.crate_name, self.sess.local_crate_disambiguator()) + let (crate_name, stable_crate_id) = if def_id.is_local() { + (self.crate_name, self.sess.local_stable_crate_id()) } else { ( self.cstore.crate_name_untracked(def_id.krate), - self.cstore.crate_disambiguator_untracked(def_id.krate), + self.def_path_hash(def_id.krate.as_def_id()).stable_crate_id(), ) }; format!( "{}[{}]{}", crate_name, - // Don't print the whole crate disambiguator. That's just + // Don't print the whole stable crate id. That's just // annoying in debug output. - &(crate_disambiguator.to_fingerprint().to_hex())[..4], + &(format!("{:08x}", stable_crate_id.to_u64()))[..4], self.def_path(def_id).to_string_no_crate_verbose() ) } @@ -2657,8 +2645,10 @@ impl<'tcx> TyCtxt<'tcx> { struct_lint_level(self.sess, lint, level, src, None, decorate); } - pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx StableVec<TraitCandidate>> { - self.in_scope_traits_map(id.owner).and_then(|map| map.get(&id.local_id)) + pub fn in_scope_traits(self, id: HirId) -> Option<&'tcx [TraitCandidate]> { + let map = self.in_scope_traits_map(id.owner)?; + let candidates = map.get(&id.local_id)?; + Some(&*candidates) } pub fn named_region(self, id: HirId) -> Option<resolve_lifetime::Region> { @@ -2788,7 +2778,7 @@ fn ptr_eq<T, U>(t: *const T, u: *const U) -> bool { } pub fn provide(providers: &mut ty::query::Providers) { - providers.in_scope_traits_map = |tcx, id| tcx.gcx.trait_map.get(&id); + providers.in_scope_traits_map = |tcx, id| tcx.hir_crate(()).trait_map.get(&id); providers.module_exports = |tcx, id| tcx.gcx.export_map.get(&id).map(|v| &v[..]); providers.crate_name = |tcx, id| { assert_eq!(id, LOCAL_CRATE); diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index c8fdbc30d15..4e3f475a915 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -93,6 +93,7 @@ pub struct Generics { } impl<'tcx> Generics { + #[inline] pub fn count(&self) -> usize { self.parent_count + self.params.len() } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index c2e9dba6c8e..03a026500d7 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2579,7 +2579,7 @@ where fn adjust_for_abi(&mut self, cx: &C, abi: SpecAbi); } -fn fn_can_unwind( +pub fn fn_can_unwind( panic_strategy: PanicStrategy, codegen_fn_attr_flags: CodegenFnAttrFlags, call_conv: Conv, @@ -2641,6 +2641,43 @@ fn fn_can_unwind( } } +pub fn conv_from_spec_abi(tcx: TyCtxt<'_>, abi: SpecAbi) -> Conv { + use rustc_target::spec::abi::Abi::*; + match tcx.sess.target.adjust_abi(abi) { + RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, + + // It's the ABI's job to select this, not ours. + System { .. } => bug!("system abi should be selected elsewhere"), + EfiApi => bug!("eficall abi should be selected elsewhere"), + + Stdcall { .. } => Conv::X86Stdcall, + Fastcall => Conv::X86Fastcall, + Vectorcall => Conv::X86VectorCall, + Thiscall { .. } => Conv::X86ThisCall, + C { .. } => Conv::C, + Unadjusted => Conv::C, + Win64 => Conv::X86_64Win64, + SysV64 => Conv::X86_64SysV, + Aapcs => Conv::ArmAapcs, + CCmseNonSecureCall => Conv::CCmseNonSecureCall, + PtxKernel => Conv::PtxKernel, + Msp430Interrupt => Conv::Msp430Intr, + X86Interrupt => Conv::X86Intr, + AmdGpuKernel => Conv::AmdGpuKernel, + AvrInterrupt => Conv::AvrInterrupt, + AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt, + Wasm => Conv::C, + + // These API constants ought to be more specific... + Cdecl => Conv::C, + } +} + +pub fn fn_ptr_codegen_fn_attr_flags() -> CodegenFnAttrFlags { + // Assume that fn pointers may always unwind + CodegenFnAttrFlags::UNWIND +} + impl<'tcx, C> FnAbiExt<'tcx, C> for call::FnAbi<'tcx, Ty<'tcx>> where C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout = TyAndLayout<'tcx>> @@ -2650,10 +2687,7 @@ where + HasParamEnv<'tcx>, { fn of_fn_ptr(cx: &C, sig: ty::PolyFnSig<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { - // Assume that fn pointers may always unwind - let codegen_fn_attr_flags = CodegenFnAttrFlags::UNWIND; - - call::FnAbi::new_internal(cx, sig, extra_args, None, codegen_fn_attr_flags, false) + call::FnAbi::new_internal(cx, sig, extra_args, None, fn_ptr_codegen_fn_attr_flags(), false) } fn of_instance(cx: &C, instance: ty::Instance<'tcx>, extra_args: &[Ty<'tcx>]) -> Self { @@ -2689,35 +2723,7 @@ where let sig = cx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig); - use rustc_target::spec::abi::Abi::*; - let conv = match cx.tcx().sess.target.adjust_abi(sig.abi) { - RustIntrinsic | PlatformIntrinsic | Rust | RustCall => Conv::Rust, - - // It's the ABI's job to select this, not ours. - System { .. } => bug!("system abi should be selected elsewhere"), - EfiApi => bug!("eficall abi should be selected elsewhere"), - - Stdcall { .. } => Conv::X86Stdcall, - Fastcall => Conv::X86Fastcall, - Vectorcall => Conv::X86VectorCall, - Thiscall { .. } => Conv::X86ThisCall, - C { .. } => Conv::C, - Unadjusted => Conv::C, - Win64 => Conv::X86_64Win64, - SysV64 => Conv::X86_64SysV, - Aapcs => Conv::ArmAapcs, - CCmseNonSecureCall => Conv::CCmseNonSecureCall, - PtxKernel => Conv::PtxKernel, - Msp430Interrupt => Conv::Msp430Intr, - X86Interrupt => Conv::X86Intr, - AmdGpuKernel => Conv::AmdGpuKernel, - AvrInterrupt => Conv::AvrInterrupt, - AvrNonBlockingInterrupt => Conv::AvrNonBlockingInterrupt, - Wasm => Conv::C, - - // These API constants ought to be more specific... - Cdecl => Conv::C, - }; + let conv = conv_from_spec_abi(cx.tcx(), sig.abi); let mut inputs = sig.inputs(); let extra_args = if sig.abi == RustCall { @@ -2753,6 +2759,7 @@ where target.os == "linux" && target.arch == "sparc64" && target_env_gnu_like; let linux_powerpc_gnu_like = target.os == "linux" && target.arch == "powerpc" && target_env_gnu_like; + use SpecAbi::*; let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall); // Handle safe Rust thin and fat pointers. diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index e657088a5e4..44dfcbf1866 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -37,9 +37,11 @@ pub struct List<T> { unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> { const BITS: usize = std::mem::align_of::<usize>().trailing_zeros() as usize; + #[inline] fn into_usize(self) -> usize { self as *const List<T> as usize } + #[inline] unsafe fn from_usize(ptr: usize) -> Self { &*(ptr as *const List<T>) } diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 94e325e9e87..af2be37f387 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -269,7 +269,7 @@ pub struct CrateVariancesMap<'tcx> { // the types of AST nodes. #[derive(Copy, Clone, PartialEq, Eq, Hash)] pub struct CReaderCacheKey { - pub cnum: CrateNum, + pub cnum: Option<CrateNum>, pub pos: usize, } @@ -1097,12 +1097,14 @@ pub struct ParamEnv<'tcx> { unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal { const BITS: usize = 1; + #[inline] fn into_usize(self) -> usize { match self { traits::Reveal::UserFacing => 0, traits::Reveal::All => 1, } } + #[inline] unsafe fn from_usize(ptr: usize) -> Self { match ptr { 0 => traits::Reveal::UserFacing, @@ -1200,6 +1202,7 @@ impl<'tcx> ParamEnv<'tcx> { } /// Returns this same environment but with no caller bounds. + #[inline] pub fn without_caller_bounds(self) -> Self { Self::new(List::empty(), self.reveal()) } @@ -1618,7 +1621,7 @@ impl<'tcx> TyCtxt<'tcx> { fn item_name_from_def_id(self, def_id: DefId) -> Option<Symbol> { if def_id.index == CRATE_DEF_INDEX { - Some(self.original_crate_name(def_id.krate)) + Some(self.crate_name(def_id.krate)) } else { let def_key = self.def_key(def_id); match def_key.disambiguated_data.data { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 76c48597092..25557bdd100 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,5 +1,5 @@ use crate::middle::cstore::{ExternCrate, ExternCrateSource}; -use crate::mir::interpret::{AllocId, ConstValue, GlobalAlloc, Pointer, Scalar}; +use crate::mir::interpret::{AllocRange, ConstValue, GlobalAlloc, Pointer, Scalar}; use crate::ty::subst::{GenericArg, GenericArgKind, Subst}; use crate::ty::{self, ConstInt, DefIdTree, ParamConst, ScalarInt, Ty, TyCtxt, TypeFoldable}; use rustc_apfloat::ieee::{Double, Single}; @@ -452,7 +452,7 @@ pub trait PrettyPrinter<'tcx>: } // Re-exported `extern crate` (#43189). DefPathData::CrateRoot => { - data = DefPathData::TypeNs(self.tcx().original_crate_name(def_id.krate)); + data = DefPathData::TypeNs(self.tcx().crate_name(def_id.krate)); } _ => {} } @@ -1004,9 +1004,9 @@ pub trait PrettyPrinter<'tcx>: _, ) => match self.tcx().get_global_alloc(ptr.alloc_id) { Some(GlobalAlloc::Memory(alloc)) => { - let bytes = int.assert_bits(self.tcx().data_layout.pointer_size); - let size = Size::from_bytes(bytes); - if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), ptr, size) { + let len = int.assert_bits(self.tcx().data_layout.pointer_size); + let range = AllocRange { start: ptr.offset, size: Size::from_bytes(len) }; + if let Ok(byte_str) = alloc.get_bytes(&self.tcx(), range) { p!(pretty_print_byte_str(byte_str)) } else { p!("<too short allocation>") @@ -1181,10 +1181,9 @@ pub trait PrettyPrinter<'tcx>: (ConstValue::ByRef { alloc, offset }, ty::Array(t, n)) if *t == u8_type => { let n = n.val.try_to_bits(self.tcx().data_layout.pointer_size).unwrap(); // cast is ok because we already checked for pointer size (32 or 64 bit) above - let n = Size::from_bytes(n); - let ptr = Pointer::new(AllocId(0), offset); + let range = AllocRange { start: offset, size: Size::from_bytes(n) }; - let byte_str = alloc.get_bytes(&self.tcx(), ptr, n).unwrap(); + let byte_str = alloc.get_bytes(&self.tcx(), range).unwrap(); p!("*"); p!(pretty_print_byte_str(byte_str)); Ok(self) diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index 3c772a14647..a5b540dcb70 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -18,6 +18,7 @@ use crate::mir::interpret::GlobalId; use crate::mir::interpret::{ConstAlloc, LitToConstError, LitToConstInput}; use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult}; use crate::mir::mono::CodegenUnit; +use crate::thir; use crate::traits::query::{ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, @@ -33,7 +34,6 @@ use crate::ty::subst::{GenericArg, SubstsRef}; use crate::ty::util::AlwaysRequiresDrop; use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap}; -use rustc_data_structures::stable_hasher::StableVec; use rustc_data_structures::steal::Steal; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::Lrc; @@ -47,7 +47,6 @@ use rustc_index::{bit_set::FiniteBitSet, vec::IndexVec}; use rustc_serialize::opaque; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_session::utils::NativeLibKind; -use rustc_session::CrateDisambiguator; use rustc_target::spec::PanicStrategy; use rustc_ast as ast; diff --git a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs index a688b816e9a..e473559812f 100644 --- a/compiler/rustc_middle/src/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -18,7 +18,7 @@ use rustc_serialize::{ opaque::{self, FileEncodeResult, FileEncoder, IntEncodedWithFixedSize}, Decodable, Decoder, Encodable, Encoder, }; -use rustc_session::{CrateDisambiguator, Session}; +use rustc_session::{Session, StableCrateId}; use rustc_span::hygiene::{ ExpnDataDecodeMode, ExpnDataEncodeMode, ExpnId, HygieneDecodeContext, HygieneEncodeContext, SyntaxContext, SyntaxContextData, @@ -52,7 +52,7 @@ pub struct OnDiskCache<'sess> { // session. current_diagnostics: Lock<FxHashMap<DepNodeIndex, Vec<Diagnostic>>>, - prev_cnums: Vec<(u32, String, CrateDisambiguator)>, + prev_cnums: Vec<(u32, StableCrateId)>, cnum_map: OnceCell<IndexVec<CrateNum, Option<CrateNum>>>, source_map: &'sess SourceMap, @@ -120,7 +120,7 @@ pub struct OnDiskCache<'sess> { #[derive(Encodable, Decodable)] struct Footer { file_index_to_stable_id: FxHashMap<SourceFileIndex, StableSourceFileId>, - prev_cnums: Vec<(u32, String, CrateDisambiguator)>, + prev_cnums: Vec<(u32, StableCrateId)>, query_result_index: EncodedQueryResultIndex, diagnostics_index: EncodedQueryResultIndex, // The location of all allocations. @@ -349,9 +349,8 @@ impl<'sess> OnDiskCache<'sess> { let prev_cnums: Vec<_> = sorted_cnums .iter() .map(|&cnum| { - let crate_name = tcx.original_crate_name(cnum).to_string(); - let crate_disambiguator = tcx.crate_disambiguator(cnum); - (cnum.as_u32(), crate_name, crate_disambiguator) + let stable_crate_id = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); + (cnum.as_u32(), stable_crate_id) }) .collect(); @@ -575,25 +574,23 @@ impl<'sess> OnDiskCache<'sess> { // maps to None. fn compute_cnum_map( tcx: TyCtxt<'_>, - prev_cnums: &[(u32, String, CrateDisambiguator)], + prev_cnums: &[(u32, StableCrateId)], ) -> IndexVec<CrateNum, Option<CrateNum>> { tcx.dep_graph.with_ignore(|| { let current_cnums = tcx .all_crate_nums(()) .iter() .map(|&cnum| { - let crate_name = tcx.original_crate_name(cnum).to_string(); - let crate_disambiguator = tcx.crate_disambiguator(cnum); - ((crate_name, crate_disambiguator), cnum) + let stable_crate_id = tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); + (stable_crate_id, cnum) }) .collect::<FxHashMap<_, _>>(); let map_size = prev_cnums.iter().map(|&(cnum, ..)| cnum).max().unwrap_or(0) + 1; let mut map = IndexVec::from_elem_n(None, map_size as usize); - for &(prev_cnum, ref crate_name, crate_disambiguator) in prev_cnums { - let key = (crate_name.clone(), crate_disambiguator); - map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&key).cloned(); + for &(prev_cnum, stable_crate_id) in prev_cnums { + map[CrateNum::from_u32(prev_cnum)] = current_cnums.get(&stable_crate_id).cloned(); } map[LOCAL_CRATE] = Some(LOCAL_CRATE); @@ -758,8 +755,7 @@ impl<'a, 'tcx> TyDecoder<'tcx> for CacheDecoder<'a, 'tcx> { { let tcx = self.tcx(); - let cache_key = - ty::CReaderCacheKey { cnum: CrateNum::ReservedForIncrCompCache, pos: shorthand }; + let cache_key = ty::CReaderCacheKey { cnum: None, pos: shorthand }; if let Some(&ty) = tcx.ty_rcache.borrow().get(&cache_key) { return Ok(ty); diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 691bfcc98d1..012d9bd82c8 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -669,7 +669,7 @@ impl<'tcx> GeneratorSubsts<'tcx> { } } -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, HashStable)] pub enum UpvarSubsts<'tcx> { Closure(SubstsRef<'tcx>), Generator(SubstsRef<'tcx>), @@ -1837,10 +1837,12 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_enum(&self) -> bool { - match self.kind() { - Adt(adt_def, _) => adt_def.is_enum(), - _ => false, - } + matches!(self.kind(), Adt(adt_def, _) if adt_def.is_enum()) + } + + #[inline] + pub fn is_union(&self) -> bool { + matches!(self.kind(), Adt(adt_def, _) if adt_def.is_union()) } #[inline] diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs index c84ca61122f..9b8d22d8eaf 100644 --- a/compiler/rustc_middle/src/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -197,7 +197,7 @@ impl<'a, 'tcx> InternalSubsts<'tcx> { } /// Interpret these substitutions as the substitutions of a generator type. - /// Closure substitutions have a particular structure controlled by the + /// Generator substitutions have a particular structure controlled by the /// compiler that encodes information like the signature and generator kind; /// see `ty::GeneratorSubsts` struct for more comments. pub fn as_generator(&'tcx self) -> GeneratorSubsts<'tcx> { diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 30e0b293ffb..8b0761889b8 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -4,10 +4,9 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{AsyncGeneratorKind, GeneratorKind}; -use rustc_index::vec::Idx; use rustc_middle::mir::{ self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory, - FakeReadCause, Local, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, + FakeReadCause, LocalDecl, LocalInfo, LocalKind, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm, }; use rustc_middle::ty::{self, suggest_constraining_type_param, Ty, TypeFoldable}; @@ -1274,7 +1273,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { bug!("temporary or return pointer with a name") } LocalKind::Var => "local variable ", - LocalKind::Arg if !self.upvars.is_empty() && local == Local::new(1) => { + LocalKind::Arg + if !self.upvars.is_empty() && local == ty::CAPTURE_STRUCT_LOCAL => + { "variable captured by `move` " } LocalKind::Arg => "function parameter ", diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index 1e2714a2c1b..d2b15661047 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -1,6 +1,5 @@ use rustc_hir as hir; use rustc_hir::Node; -use rustc_index::vec::Idx; use rustc_middle::hir::map::Map; use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; use rustc_middle::ty::{self, Ty, TyCtxt}; @@ -115,12 +114,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } PlaceRef { local: _, projection: [proj_base @ .., ProjectionElem::Deref] } => { - if the_place_err.local == Local::new(1) + if the_place_err.local == ty::CAPTURE_STRUCT_LOCAL && proj_base.is_empty() && !self.upvars.is_empty() { item_msg = format!("`{}`", access_place_desc.unwrap()); - debug_assert!(self.body.local_decls[Local::new(1)].ty.is_region_ptr()); + debug_assert!( + self.body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty.is_region_ptr() + ); debug_assert!(is_closure_or_generator( Place::ty_from( the_place_err.local, @@ -478,11 +479,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } - PlaceRef { - local, - projection: [ProjectionElem::Deref], - // FIXME document what is this 1 magic number about - } if local == Local::new(1) && !self.upvars.is_empty() => { + PlaceRef { local, projection: [ProjectionElem::Deref] } + if local == ty::CAPTURE_STRUCT_LOCAL && !self.upvars.is_empty() => + { self.expected_fn_found_fn_mut_call(&mut err, span, act); } diff --git a/compiler/rustc_mir/src/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs index 4c35be39a3d..36eb8a4baa8 100644 --- a/compiler/rustc_mir/src/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -1965,13 +1965,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // no move out from an earlier location) then this is an attempt at initialization // of the union - we should error in that case. let tcx = this.infcx.tcx; - if let ty::Adt(def, _) = base.ty(this.body(), tcx).ty.kind() { - if def.is_union() { - if this.move_data.path_map[mpi].iter().any(|moi| { - this.move_data.moves[*moi].source.is_predecessor_of(location, this.body) - }) { - return; - } + if base.ty(this.body(), tcx).ty.is_union() { + if this.move_data.path_map[mpi].iter().any(|moi| { + this.move_data.moves[*moi].source.is_predecessor_of(location, this.body) + }) { + return; } } diff --git a/compiler/rustc_mir/src/borrow_check/places_conflict.rs b/compiler/rustc_mir/src/borrow_check/places_conflict.rs index 3654b51949e..d21550a8e1a 100644 --- a/compiler/rustc_mir/src/borrow_check/places_conflict.rs +++ b/compiler/rustc_mir/src/borrow_check/places_conflict.rs @@ -331,17 +331,14 @@ fn place_projection_conflict<'tcx>( Overlap::EqualOrDisjoint } else { let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty; - match ty.kind() { - ty::Adt(def, _) if def.is_union() => { - // Different fields of a union, we are basically stuck. - debug!("place_element_conflict: STUCK-UNION"); - Overlap::Arbitrary - } - _ => { - // Different fields of a struct (`a.x` vs. `a.y`). Disjoint! - debug!("place_element_conflict: DISJOINT-FIELD"); - Overlap::Disjoint - } + if ty.is_union() { + // Different fields of a union, we are basically stuck. + debug!("place_element_conflict: STUCK-UNION"); + Overlap::Arbitrary + } else { + // Different fields of a struct (`a.x` vs. `a.y`). Disjoint! + debug!("place_element_conflict: DISJOINT-FIELD"); + Overlap::Disjoint } } } diff --git a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs index bbd512fd360..f4d78ac04cb 100644 --- a/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs @@ -1241,7 +1241,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// it. However, it works pretty well in practice. In particular, /// this is needed to deal with projection outlives bounds like /// - /// ```ignore (internal compiler representation so lifetime syntax is invalid) + /// ```text /// <T as Foo<'0>>::Item: '1 /// ``` /// diff --git a/compiler/rustc_mir/src/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs index 754ed0bea84..fc21047ab72 100644 --- a/compiler/rustc_mir/src/const_eval/error.rs +++ b/compiler/rustc_mir/src/const_eval/error.rs @@ -9,7 +9,7 @@ use rustc_span::{Span, Symbol}; use super::InterpCx; use crate::interpret::{ - struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, + struct_error, ErrorHandled, FrameInfo, InterpError, InterpErrorInfo, Machine, MachineStopType, }; /// The CTFE machine has some custom error kinds. @@ -24,12 +24,21 @@ pub enum ConstEvalErrKind { Abort(String), } +impl MachineStopType for ConstEvalErrKind { + fn is_hard_err(&self) -> bool { + match self { + Self::Panic { .. } => true, + _ => false, + } + } +} + // The errors become `MachineStop` with plain strings when being raised. // `ConstEvalErr` (in `librustc_middle/mir/interpret/error.rs`) knows to // handle these. impl<'tcx> Into<InterpErrorInfo<'tcx>> for ConstEvalErrKind { fn into(self) -> InterpErrorInfo<'tcx> { - err_machine_stop!(self.to_string()).into() + err_machine_stop!(self).into() } } @@ -148,31 +157,10 @@ impl<'tcx> ConstEvalErr<'tcx> { tcx: TyCtxtAt<'tcx>, message: &str, emit: impl FnOnce(DiagnosticBuilder<'_>), - lint_root: Option<hir::HirId>, + mut lint_root: Option<hir::HirId>, ) -> ErrorHandled { - let must_error = match self.error { - err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { - return ErrorHandled::TooGeneric; - } - err_inval!(AlreadyReported(error_reported)) => { - return ErrorHandled::Reported(error_reported); - } - // We must *always* hard error on these, even if the caller wants just a lint. - err_inval!(Layout(LayoutError::SizeOverflow(_))) => true, - _ => false, - }; - trace!("reporting const eval failure at {:?}", self.span); - - let err_msg = match &self.error { - InterpError::MachineStop(msg) => { - // A custom error (`ConstEvalErrKind` in `librustc_mir/interp/const_eval/error.rs`). - // Should be turned into a string by now. - msg.downcast_ref::<String>().expect("invalid MachineStop payload").clone() - } - err => err.to_string(), - }; - let finish = |mut err: DiagnosticBuilder<'_>, span_msg: Option<String>| { + trace!("reporting const eval failure at {:?}", self.span); if let Some(span_msg) = span_msg { err.span_label(self.span, span_msg); } @@ -186,34 +174,50 @@ impl<'tcx> ConstEvalErr<'tcx> { emit(err) }; - if must_error { - // The `message` makes little sense here, this is a more serious error than the - // caller thinks anyway. - // See <https://github.com/rust-lang/rust/pull/63152>. - finish(struct_error(tcx, &err_msg), None); - ErrorHandled::Reported(ErrorReported) - } else { - // Regular case. - if let Some(lint_root) = lint_root { - // Report as lint. - let hir_id = self - .stacktrace - .iter() - .rev() - .find_map(|frame| frame.lint_root) - .unwrap_or(lint_root); - tcx.struct_span_lint_hir( - rustc_session::lint::builtin::CONST_ERR, - hir_id, - tcx.span, - |lint| finish(lint.build(message), Some(err_msg)), - ); - ErrorHandled::Linted - } else { - // Report as hard error. - finish(struct_error(tcx, message), Some(err_msg)); - ErrorHandled::Reported(ErrorReported) + // Special handling for certain errors + match &self.error { + // Don't emit a new diagnostic for these errors + err_inval!(Layout(LayoutError::Unknown(_))) | err_inval!(TooGeneric) => { + return ErrorHandled::TooGeneric; + } + err_inval!(AlreadyReported(error_reported)) => { + return ErrorHandled::Reported(*error_reported); + } + err_inval!(Layout(LayoutError::SizeOverflow(_))) => { + // We must *always* hard error on these, even if the caller wants just a lint. + // The `message` makes little sense here, this is a more serious error than the + // caller thinks anyway. + // See <https://github.com/rust-lang/rust/pull/63152>. + finish(struct_error(tcx, &self.error.to_string()), None); + return ErrorHandled::Reported(ErrorReported); } + _ => {} + }; + + // If we have a 'hard error', then set `lint_root` to `None` so that we don't + // emit a lint. + if matches!(&self.error, InterpError::MachineStop(err) if err.is_hard_err()) { + lint_root = None; + } + + let err_msg = self.error.to_string(); + + // Regular case - emit a lint. + if let Some(lint_root) = lint_root { + // Report as lint. + let hir_id = + self.stacktrace.iter().rev().find_map(|frame| frame.lint_root).unwrap_or(lint_root); + tcx.struct_span_lint_hir( + rustc_session::lint::builtin::CONST_ERR, + hir_id, + tcx.span, + |lint| finish(lint.build(message), Some(err_msg)), + ); + ErrorHandled::Linted + } else { + // Report as hard error. + finish(struct_error(tcx, message), Some(err_msg)); + ErrorHandled::Reported(ErrorReported) } } } diff --git a/compiler/rustc_mir/src/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs index d51adc8864d..460fea37461 100644 --- a/compiler/rustc_mir/src/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -16,6 +16,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, subst::Subst, TyCtxt}; use rustc_span::source_map::Span; use rustc_target::abi::{Abi, LayoutOf}; +use std::borrow::Cow; use std::convert::TryInto; pub fn note_on_undefined_behavior_error() -> &'static str { @@ -169,8 +170,9 @@ pub(super) fn op_to_const<'tcx>( (ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(), ptr.offset.bytes()) } Scalar::Int { .. } => ( - ecx.tcx - .intern_const_alloc(Allocation::from_byte_aligned_bytes(b"" as &[u8])), + ecx.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable( + b"" as &[u8], + )), 0, ), }; @@ -327,11 +329,22 @@ pub fn eval_to_allocation_raw_provider<'tcx>( )) } else { let msg = if is_static { - "could not evaluate static initializer" + Cow::from("could not evaluate static initializer") } else { - "evaluation of constant value failed" + // If the current item has generics, we'd like to enrich the message with the + // instance and its substs: to show the actual compile-time values, in addition to + // the expression, leading to the const eval error. + let instance = &key.value.instance; + if !instance.substs.is_empty() { + let instance = with_no_trimmed_paths(|| instance.to_string()); + let msg = format!("evaluation of `{}` failed", instance); + Cow::from(msg) + } else { + Cow::from("evaluation of constant value failed") + } }; - Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), msg)) + + Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), &msg)) } } Ok(mplace) => { diff --git a/compiler/rustc_mir/src/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs index 8e9148f5b66..773df7d7b60 100644 --- a/compiler/rustc_mir/src/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -17,7 +17,7 @@ use rustc_target::spec::abi::Abi; use crate::interpret::{ self, compile_time_machine, AllocId, Allocation, Frame, ImmTy, InterpCx, InterpResult, Memory, - OpTy, PlaceTy, Pointer, Scalar, + OpTy, PlaceTy, Pointer, Scalar, StackPopUnwind, }; use super::error::*; @@ -223,7 +223,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, _abi: Abi, args: &[OpTy<'tcx>], _ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>, - _unwind: Option<mir::BasicBlock>, // unwinding is not supported in consts + _unwind: StackPopUnwind, // unwinding is not supported in consts ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { debug!("find_mir_or_eval_fn: {:?}", instance); @@ -263,7 +263,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], ret: Option<(&PlaceTy<'tcx>, mir::BasicBlock)>, - _unwind: Option<mir::BasicBlock>, + _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { // Shared intrinsics. if ecx.emulate_intrinsic(instance, args, ret)? { diff --git a/compiler/rustc_mir/src/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs index 3f14efc920f..6a514e9f62f 100644 --- a/compiler/rustc_mir/src/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -181,7 +181,7 @@ pub(crate) fn deref_const<'tcx>( let mplace = ecx.deref_operand(&op).unwrap(); if let Scalar::Ptr(ptr) = mplace.ptr { assert_eq!( - ecx.memory.get_raw(ptr.alloc_id).unwrap().mutability, + tcx.get_global_alloc(ptr.alloc_id).unwrap().unwrap_memory().mutability, Mutability::Not, "deref_const cannot be used with mutable allocations as \ that could allow pattern matching to observe mutable statics", diff --git a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs index 1bfbb843114..cea465ea1ed 100644 --- a/compiler/rustc_mir/src/dataflow/move_paths/builder.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs @@ -519,10 +519,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // Check if we are assigning into a field of a union, if so, lookup the place // of the union so it is marked as initialized again. if let Some((place_base, ProjectionElem::Field(_, _))) = place.last_projection() { - if let ty::Adt(def, _) = place_base.ty(self.builder.body, self.builder.tcx).ty.kind() { - if def.is_union() { - place = place_base; - } + if place_base.ty(self.builder.body, self.builder.tcx).ty.is_union() { + place = place_base; } } diff --git a/compiler/rustc_mir/src/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs index e9dd7a3fe68..6f7519e6156 100644 --- a/compiler/rustc_mir/src/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -134,14 +134,25 @@ pub struct FrameInfo<'tcx> { pub lint_root: Option<hir::HirId>, } -#[derive(Clone, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these +/// Unwind information. +#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] +pub enum StackPopUnwind { + /// The cleanup block. + Cleanup(mir::BasicBlock), + /// No cleanup needs to be done. + Skip, + /// Unwinding is not allowed (UB). + NotAllowed, +} + +#[derive(Clone, Copy, Eq, PartialEq, Debug, HashStable)] // Miri debug-prints these pub enum StackPopCleanup { /// Jump to the next block in the caller, or cause UB if None (that's a function /// that may never return). Also store layout of return place so /// we can validate it at that layout. /// `ret` stores the block we jump to on a normal return, while `unwind` /// stores the block used for cleanup during unwinding. - Goto { ret: Option<mir::BasicBlock>, unwind: Option<mir::BasicBlock> }, + Goto { ret: Option<mir::BasicBlock>, unwind: StackPopUnwind }, /// Just do nothing: Used by Main and for the `box_alloc` hook in miri. /// `cleanup` says whether locals are deallocated. Static computation /// wants them leaked to intern what they need (and just throw away @@ -746,13 +757,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// *Unwind* to the given `target` basic block. /// Do *not* use for returning! Use `return_to_block` instead. /// - /// If `target` is `None`, that indicates the function does not need cleanup during - /// unwinding, and we will just keep propagating that upwards. - pub fn unwind_to_block(&mut self, target: Option<mir::BasicBlock>) { + /// If `target` is `StackPopUnwind::Skip`, that indicates the function does not need cleanup + /// during unwinding, and we will just keep propagating that upwards. + /// + /// If `target` is `StackPopUnwind::NotAllowed`, that indicates the function does not allow + /// unwinding, and doing so is UB. + pub fn unwind_to_block(&mut self, target: StackPopUnwind) -> InterpResult<'tcx> { self.frame_mut().loc = match target { - Some(block) => Ok(mir::Location { block, statement_index: 0 }), - None => Err(self.frame_mut().body.span), + StackPopUnwind::Cleanup(block) => Ok(mir::Location { block, statement_index: 0 }), + StackPopUnwind::Skip => Err(self.frame_mut().body.span), + StackPopUnwind::NotAllowed => { + throw_ub_format!("unwinding past a stack frame that does not allow unwinding") + } }; + Ok(()) } /// Pops the current frame from the stack, deallocating the @@ -801,21 +819,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } } + let return_to_block = frame.return_to_block; + // Now where do we jump next? // Usually we want to clean up (deallocate locals), but in a few rare cases we don't. // In that case, we return early. We also avoid validation in that case, // because this is CTFE and the final value will be thoroughly validated anyway. - let (cleanup, next_block) = match frame.return_to_block { - StackPopCleanup::Goto { ret, unwind } => { - (true, Some(if unwinding { unwind } else { ret })) - } - StackPopCleanup::None { cleanup, .. } => (cleanup, None), + let cleanup = match return_to_block { + StackPopCleanup::Goto { .. } => true, + StackPopCleanup::None { cleanup, .. } => cleanup, }; if !cleanup { assert!(self.stack().is_empty(), "only the topmost frame should ever be leaked"); - assert!(next_block.is_none(), "tried to skip cleanup when we have a next block!"); assert!(!unwinding, "tried to skip cleanup during unwinding"); // Leak the locals, skip validation, skip machine hook. return Ok(()); @@ -834,16 +851,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Normal return, figure out where to jump. if unwinding { // Follow the unwind edge. - let unwind = next_block.expect("Encountered StackPopCleanup::None when unwinding!"); - self.unwind_to_block(unwind); + let unwind = match return_to_block { + StackPopCleanup::Goto { unwind, .. } => unwind, + StackPopCleanup::None { .. } => { + panic!("Encountered StackPopCleanup::None when unwinding!") + } + }; + self.unwind_to_block(unwind) } else { // Follow the normal return edge. - if let Some(ret) = next_block { - self.return_to_block(ret)?; + match return_to_block { + StackPopCleanup::Goto { ret, .. } => self.return_to_block(ret), + StackPopCleanup::None { .. } => Ok(()), } } - - Ok(()) } /// Mark a storage as live, killing the previous content. diff --git a/compiler/rustc_mir/src/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs index 69ab50fa86e..99622fb310a 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -14,7 +14,7 @@ use rustc_middle::ty; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::{Abi, LayoutOf as _, Primitive, Size}; +use rustc_target::abi::{Abi, Align, LayoutOf as _, Primitive, Size}; use super::{ util::ensure_monomorphic_enough, CheckInAllocMsg, ImmTy, InterpCx, Machine, OpTy, PlaceTy, @@ -525,7 +525,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.memory.check_ptr_access_align( min_ptr, Size::from_bytes(size), - None, + Align::ONE, CheckInAllocMsg::PointerArithmeticTest, )?; Ok(offset_ptr) @@ -549,17 +549,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { ) })?; - // Make sure we check both pointers for an access of the total size and aligment, - // *even if* the total size is 0. - let src = - self.memory.check_ptr_access(self.read_scalar(&src)?.check_init()?, size, align)?; + let src = self.read_scalar(&src)?.check_init()?; + let dst = self.read_scalar(&dst)?.check_init()?; - let dst = - self.memory.check_ptr_access(self.read_scalar(&dst)?.check_init()?, size, align)?; - - if let (Some(src), Some(dst)) = (src, dst) { - self.memory.copy(src, dst, size, nonoverlapping)?; - } - Ok(()) + self.memory.copy(src, align, dst, align, size, nonoverlapping) } } diff --git a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs index 2b996cf62a3..792a4749108 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs @@ -1,5 +1,6 @@ use std::convert::TryFrom; +use rustc_ast::Mutability; use rustc_hir::lang_items::LangItem; use rustc_middle::mir::TerminatorKind; use rustc_middle::ty::subst::Subst; @@ -79,7 +80,8 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { line: u32, col: u32, ) -> MPlaceTy<'tcx, M::PointerTag> { - let file = self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation); + let file = + self.allocate_str(&filename.as_str(), MemoryKind::CallerLocation, Mutability::Not); let line = Scalar::from_u32(line); let col = Scalar::from_u32(col); diff --git a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs index ae5e78ee33f..a7012cd63f3 100644 --- a/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs @@ -1,5 +1,5 @@ use rustc_hir::def_id::CrateNum; -use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_hir::definitions::DisambiguatedDefPathData; use rustc_middle::mir::interpret::Allocation; use rustc_middle::ty::{ self, @@ -88,7 +88,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { } fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { - self.path.push_str(&self.tcx.original_crate_name(cnum).as_str()); + self.path.push_str(&self.tcx.crate_name(cnum).as_str()); Ok(self) } @@ -127,11 +127,6 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { ) -> Result<Self::Path, Self::Error> { self = print_prefix(self)?; - // Skip `::{{constructor}}` on tuple/unit structs. - if disambiguated_data.data == DefPathData::Ctor { - return Ok(self); - } - write!(self.path, "::{}", disambiguated_data.data).unwrap(); Ok(self) @@ -197,6 +192,6 @@ impl Write for AbsolutePathPrinter<'_> { /// Directly returns an `Allocation` containing an absolute path representation of the given type. crate fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> &'tcx Allocation { let path = AbsolutePathPrinter { tcx, path: String::new() }.print_type(ty).unwrap().path; - let alloc = Allocation::from_byte_aligned_bytes(path.into_bytes()); + let alloc = Allocation::from_bytes_byte_aligned_immutable(path.into_bytes()); tcx.intern_const_alloc(alloc) } diff --git a/compiler/rustc_mir/src/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs index 52baf1a6330..0d01dc3c219 100644 --- a/compiler/rustc_mir/src/interpret/machine.rs +++ b/compiler/rustc_mir/src/interpret/machine.rs @@ -13,8 +13,8 @@ use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use super::{ - AllocId, Allocation, AllocationExtra, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult, - LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar, + AllocId, Allocation, CheckInAllocMsg, Frame, ImmTy, InterpCx, InterpResult, LocalValue, + MemPlace, Memory, MemoryKind, OpTy, Operand, PlaceTy, Pointer, Scalar, StackPopUnwind, }; /// Data returned by Machine::stack_pop, @@ -105,7 +105,7 @@ pub trait Machine<'mir, 'tcx>: Sized { type MemoryExtra; /// Extra data stored in every allocation. - type AllocExtra: AllocationExtra<Self::PointerTag> + 'static; + type AllocExtra: Debug + Clone + 'static; /// Memory's allocation map type MemoryMap: AllocMap< @@ -132,6 +132,11 @@ pub trait Machine<'mir, 'tcx>: Sized { /// Whether to enforce the validity invariant fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool; + /// Whether function calls should be [ABI](Abi)-checked. + fn enforce_abi(_ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + true + } + /// Entry point for obtaining the MIR of anything that should get evaluated. /// So not just functions and shims, but also const/static initializers, anonymous /// constants, ... @@ -158,7 +163,7 @@ pub trait Machine<'mir, 'tcx>: Sized { abi: Abi, args: &[OpTy<'tcx, Self::PointerTag>], ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, - unwind: Option<mir::BasicBlock>, + unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>>; /// Execute `fn_val`. It is the hook's responsibility to advance the instruction @@ -169,7 +174,7 @@ pub trait Machine<'mir, 'tcx>: Sized { abi: Abi, args: &[OpTy<'tcx, Self::PointerTag>], ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, - unwind: Option<mir::BasicBlock>, + unwind: StackPopUnwind, ) -> InterpResult<'tcx>; /// Directly process an intrinsic without pushing a stack frame. It is the hook's @@ -179,7 +184,7 @@ pub trait Machine<'mir, 'tcx>: Sized { instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Self::PointerTag>], ret: Option<(&PlaceTy<'tcx, Self::PointerTag>, mir::BasicBlock)>, - unwind: Option<mir::BasicBlock>, + unwind: StackPopUnwind, ) -> InterpResult<'tcx>; /// Called to evaluate `Assert` MIR terminators that trigger a panic. @@ -305,10 +310,39 @@ pub trait Machine<'mir, 'tcx>: Sized { kind: Option<MemoryKind<Self::MemoryKind>>, ) -> (Cow<'b, Allocation<Self::PointerTag, Self::AllocExtra>>, Self::PointerTag); - /// Called to notify the machine before a deallocation occurs. - fn before_deallocation( + /// Hook for performing extra checks on a memory read access. + /// + /// Takes read-only access to the allocation so we can keep all the memory read + /// operations take `&self`. Use a `RefCell` in `AllocExtra` if you + /// need to mutate. + #[inline(always)] + fn memory_read( + _memory_extra: &Self::MemoryExtra, + _alloc_extra: &Self::AllocExtra, + _ptr: Pointer<Self::PointerTag>, + _size: Size, + ) -> InterpResult<'tcx> { + Ok(()) + } + + /// Hook for performing extra checks on a memory write access. + #[inline(always)] + fn memory_written( _memory_extra: &mut Self::MemoryExtra, - _id: AllocId, + _alloc_extra: &mut Self::AllocExtra, + _ptr: Pointer<Self::PointerTag>, + _size: Size, + ) -> InterpResult<'tcx> { + Ok(()) + } + + /// Hook for performing extra operations on a memory deallocation. + #[inline(always)] + fn memory_deallocated( + _memory_extra: &mut Self::MemoryExtra, + _alloc_extra: &mut Self::AllocExtra, + _ptr: Pointer<Self::PointerTag>, + _size: Size, ) -> InterpResult<'tcx> { Ok(()) } @@ -322,7 +356,7 @@ pub trait Machine<'mir, 'tcx>: Sized { Ok(()) } - /// Executes a retagging operation + /// Executes a retagging operation. #[inline] fn retag( _ecx: &mut InterpCx<'mir, 'tcx, Self>, @@ -422,7 +456,7 @@ pub macro compile_time_machine(<$mir: lifetime, $tcx: lifetime>) { _abi: Abi, _args: &[OpTy<$tcx>], _ret: Option<(&PlaceTy<$tcx>, mir::BasicBlock)>, - _unwind: Option<mir::BasicBlock>, + _unwind: StackPopUnwind, ) -> InterpResult<$tcx> { match fn_val {} } diff --git a/compiler/rustc_mir/src/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs index 5200e4aa90d..77de19ac674 100644 --- a/compiler/rustc_mir/src/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -18,8 +18,8 @@ use rustc_middle::ty::{Instance, ParamEnv, TyCtxt}; use rustc_target::abi::{Align, HasDataLayout, Size, TargetDataLayout}; use super::{ - AllocId, AllocMap, Allocation, AllocationExtra, CheckInAllocMsg, GlobalAlloc, InterpResult, - Machine, MayLeak, Pointer, PointerArithmetic, Scalar, + alloc_range, AllocId, AllocMap, AllocRange, Allocation, CheckInAllocMsg, GlobalAlloc, + InterpResult, Machine, MayLeak, Pointer, PointerArithmetic, Scalar, ScalarMaybeUninit, }; use crate::util::pretty; @@ -125,6 +125,24 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> HasDataLayout for Memory<'mir, 'tcx, M> } } +/// A reference to some allocation that was already bounds-checked for the given region +/// and had the on-access machine hooks run. +#[derive(Copy, Clone)] +pub struct AllocRef<'a, 'tcx, Tag, Extra> { + alloc: &'a Allocation<Tag, Extra>, + range: AllocRange, + tcx: TyCtxt<'tcx>, + alloc_id: AllocId, +} +/// A reference to some allocation that was already bounds-checked for the given region +/// and had the on-access machine hooks run. +pub struct AllocRefMut<'a, 'tcx, Tag, Extra> { + alloc: &'a mut Allocation<Tag, Extra>, + range: AllocRange, + tcx: TyCtxt<'tcx>, + alloc_id: AllocId, +} + impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { pub fn new(tcx: TyCtxt<'tcx>, extra: M::MemoryExtra) -> Self { Memory { @@ -201,9 +219,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { pub fn allocate_bytes( &mut self, bytes: &[u8], + align: Align, kind: MemoryKind<M::MemoryKind>, + mutability: Mutability, ) -> Pointer<M::PointerTag> { - let alloc = Allocation::from_byte_aligned_bytes(bytes); + let alloc = Allocation::from_bytes(bytes, align, mutability); self.allocate_with(alloc, kind) } @@ -246,7 +266,15 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Some((size, _align)) => size, None => self.get_raw(ptr.alloc_id)?.size(), }; - self.copy(ptr, new_ptr, old_size.min(new_size), /*nonoverlapping*/ true)?; + // This will also call the access hooks. + self.copy( + ptr.into(), + Align::ONE, + new_ptr.into(), + Align::ONE, + old_size.min(new_size), + /*nonoverlapping*/ true, + )?; self.deallocate(ptr, old_size_and_align, kind)?; Ok(new_ptr) @@ -278,8 +306,6 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { ); } - M::before_deallocation(&mut self.extra, ptr.alloc_id)?; - let (alloc_kind, mut alloc) = match self.alloc_map.remove(&ptr.alloc_id) { Some(alloc) => alloc, None => { @@ -297,6 +323,9 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } }; + if alloc.mutability == Mutability::Not { + throw_ub_format!("deallocating immutable allocation {}", ptr.alloc_id); + } if alloc_kind != kind { throw_ub_format!( "deallocating {}, which is {} memory, using {} deallocation operation", @@ -320,10 +349,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // Let the machine take some extra action let size = alloc.size(); - AllocationExtra::memory_deallocated(&mut alloc, ptr, size)?; + M::memory_deallocated(&mut self.extra, &mut alloc.extra, ptr, size)?; // Don't forget to remember size and align of this now-dead allocation - let old = self.dead_alloc_map.insert(ptr.alloc_id, (alloc.size(), alloc.align)); + let old = self.dead_alloc_map.insert(ptr.alloc_id, (size, alloc.align)); if old.is_some() { bug!("Nothing can be deallocated twice"); } @@ -331,40 +360,53 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { Ok(()) } - /// Check if the given scalar is allowed to do a memory access of given `size` - /// and `align`. On success, returns `None` for zero-sized accesses (where - /// nothing else is left to do) and a `Pointer` to use for the actual access otherwise. - /// Crucially, if the input is a `Pointer`, we will test it for liveness - /// *even if* the size is 0. - /// - /// Everyone accessing memory based on a `Scalar` should use this method to get the - /// `Pointer` they need. And even if you already have a `Pointer`, call this method - /// to make sure it is sufficiently aligned and not dangling. Not doing that may - /// cause ICEs. - /// - /// Most of the time you should use `check_mplace_access`, but when you just have a pointer, - /// this method is still appropriate. + /// Internal helper function for APIs that offer memory access based on `Scalar` pointers. #[inline(always)] - pub fn check_ptr_access( + pub(super) fn check_ptr_access( &self, sptr: Scalar<M::PointerTag>, size: Size, align: Align, ) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> { let align = M::enforce_alignment(&self.extra).then_some(align); - self.check_ptr_access_align(sptr, size, align, CheckInAllocMsg::MemoryAccessTest) + self.check_and_deref_ptr(sptr, size, align, CheckInAllocMsg::MemoryAccessTest, |ptr| { + let (size, align) = + self.get_size_and_align(ptr.alloc_id, AllocCheck::Dereferenceable)?; + Ok((size, align, ptr)) + }) } - /// Like `check_ptr_access`, but *definitely* checks alignment when `align` - /// is `Some` (overriding `M::enforce_alignment`). Also lets the caller control - /// the error message for the out-of-bounds case. + /// Check if the given scalar is allowed to do a memory access of given `size` and `align` + /// (ignoring `M::enforce_alignment`). The caller can control the error message for the + /// out-of-bounds case. + #[inline(always)] pub fn check_ptr_access_align( &self, sptr: Scalar<M::PointerTag>, size: Size, + align: Align, + msg: CheckInAllocMsg, + ) -> InterpResult<'tcx> { + self.check_and_deref_ptr(sptr, size, Some(align), msg, |ptr| { + let (size, align) = + self.get_size_and_align(ptr.alloc_id, AllocCheck::Dereferenceable)?; + Ok((size, align, ())) + })?; + Ok(()) + } + + /// Low-level helper function to check if a ptr is in-bounds and potentially return a reference + /// to the allocation it points to. Supports both shared and mutable references, to the actual + /// checking is offloaded to a helper closure. `align` defines whether and which alignment check + /// is done. Returns `None` for size 0, and otherwise `Some` of what `alloc_size` returned. + fn check_and_deref_ptr<T>( + &self, + sptr: Scalar<M::PointerTag>, + size: Size, align: Option<Align>, msg: CheckInAllocMsg, - ) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> { + alloc_size: impl FnOnce(Pointer<M::PointerTag>) -> InterpResult<'tcx, (Size, Align, T)>, + ) -> InterpResult<'tcx, Option<T>> { fn check_offset_align(offset: u64, align: Align) -> InterpResult<'static> { if offset % align.bytes() == 0 { Ok(()) @@ -402,8 +444,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { None } Err(ptr) => { - let (allocation_size, alloc_align) = - self.get_size_and_align(ptr.alloc_id, AllocCheck::Dereferenceable)?; + let (allocation_size, alloc_align, ret_val) = alloc_size(ptr)?; // Test bounds. This also ensures non-null. // It is sufficient to check this for the end pointer. The addition // checks for overflow. @@ -431,7 +472,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // We can still be zero-sized in this branch, in which case we have to // return `None`. - if size.bytes() == 0 { None } else { Some(ptr) } + if size.bytes() == 0 { None } else { Some(ret_val) } } }) } @@ -502,8 +543,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } /// Gives raw access to the `Allocation`, without bounds or alignment checks. - /// Use the higher-level, `PlaceTy`- and `OpTy`-based APIs in `InterpCx` instead! - pub fn get_raw( + /// The caller is responsible for calling the access hooks! + fn get_raw( &self, id: AllocId, ) -> InterpResult<'tcx, &Allocation<M::PointerTag, M::AllocExtra>> { @@ -537,21 +578,58 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } } + /// "Safe" (bounds and align-checked) allocation access. + pub fn get<'a>( + &'a self, + sptr: Scalar<M::PointerTag>, + size: Size, + align: Align, + ) -> InterpResult<'tcx, Option<AllocRef<'a, 'tcx, M::PointerTag, M::AllocExtra>>> { + let align = M::enforce_alignment(&self.extra).then_some(align); + let ptr_and_alloc = self.check_and_deref_ptr( + sptr, + size, + align, + CheckInAllocMsg::MemoryAccessTest, + |ptr| { + let alloc = self.get_raw(ptr.alloc_id)?; + Ok((alloc.size(), alloc.align, (ptr, alloc))) + }, + )?; + if let Some((ptr, alloc)) = ptr_and_alloc { + M::memory_read(&self.extra, &alloc.extra, ptr, size)?; + let range = alloc_range(ptr.offset, size); + Ok(Some(AllocRef { alloc, range, tcx: self.tcx, alloc_id: ptr.alloc_id })) + } else { + // Even in this branch we have to be sure that we actually access the allocation, in + // order to ensure that `static FOO: Type = FOO;` causes a cycle error instead of + // magically pulling *any* ZST value from the ether. However, the `get_raw` above is + // always called when `sptr` is truly a `Pointer`, so we are good. + Ok(None) + } + } + + /// Return the `extra` field of the given allocation. + pub fn get_alloc_extra<'a>(&'a self, id: AllocId) -> InterpResult<'tcx, &'a M::AllocExtra> { + Ok(&self.get_raw(id)?.extra) + } + /// Gives raw mutable access to the `Allocation`, without bounds or alignment checks. - /// Use the higher-level, `PlaceTy`- and `OpTy`-based APIs in `InterpCx` instead! - pub fn get_raw_mut( + /// The caller is responsible for calling the access hooks! + /// + /// Also returns a ptr to `self.extra` so that the caller can use it in parallel with the + /// allocation. + fn get_raw_mut( &mut self, id: AllocId, - ) -> InterpResult<'tcx, &mut Allocation<M::PointerTag, M::AllocExtra>> { + ) -> InterpResult<'tcx, (&mut Allocation<M::PointerTag, M::AllocExtra>, &mut M::MemoryExtra)> + { let tcx = self.tcx; - let memory_extra = &self.extra; + let memory_extra = &mut self.extra; let a = self.alloc_map.get_mut_or(id, || { // Need to make a copy, even if `get_global_alloc` is able // to give us a cheap reference. let alloc = Self::get_global_alloc(memory_extra, tcx, id, /*is_write*/ true)?; - if alloc.mutability == Mutability::Not { - throw_ub!(WriteToReadOnly(id)) - } let kind = M::GLOBAL_KIND.expect( "I got a global allocation that I have to copy but the machine does \ not expect that to happen", @@ -567,11 +645,41 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { if a.mutability == Mutability::Not { throw_ub!(WriteToReadOnly(id)) } - Ok(a) + Ok((a, memory_extra)) } } } + /// "Safe" (bounds and align-checked) allocation access. + pub fn get_mut<'a>( + &'a mut self, + sptr: Scalar<M::PointerTag>, + size: Size, + align: Align, + ) -> InterpResult<'tcx, Option<AllocRefMut<'a, 'tcx, M::PointerTag, M::AllocExtra>>> { + let ptr = self.check_ptr_access(sptr, size, align)?; + if let Some(ptr) = ptr { + let tcx = self.tcx; + // FIXME: can we somehow avoid looking up the allocation twice here? + // We cannot call `get_raw_mut` inside `check_and_deref_ptr` as that would duplicate `&mut self`. + let (alloc, extra) = self.get_raw_mut(ptr.alloc_id)?; + M::memory_written(extra, &mut alloc.extra, ptr, size)?; + let range = alloc_range(ptr.offset, size); + Ok(Some(AllocRefMut { alloc, range, tcx, alloc_id: ptr.alloc_id })) + } else { + Ok(None) + } + } + + /// Return the `extra` field of the given allocation. + pub fn get_alloc_extra_mut<'a>( + &'a mut self, + id: AllocId, + ) -> InterpResult<'tcx, (&'a mut M::AllocExtra, &'a mut M::MemoryExtra)> { + let (alloc, memory_extra) = self.get_raw_mut(id)?; + Ok((&mut alloc.extra, memory_extra)) + } + /// Obtain the size and alignment of an allocation, even if that allocation has /// been deallocated. /// @@ -596,7 +704,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // The caller requested no function pointers. throw_ub!(DerefFunctionPointer(id)) } else { - Ok((Size::ZERO, Align::from_bytes(1).unwrap())) + Ok((Size::ZERO, Align::ONE)) }; } @@ -658,7 +766,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } pub fn mark_immutable(&mut self, id: AllocId) -> InterpResult<'tcx> { - self.get_raw_mut(id)?.mutability = Mutability::Not; + self.get_raw_mut(id)?.0.mutability = Mutability::Not; Ok(()) } @@ -792,16 +900,62 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> std::fmt::Debug for DumpAllocs<'a, } /// Reading and writing. +impl<'tcx, 'a, Tag: Copy, Extra> AllocRefMut<'a, 'tcx, Tag, Extra> { + pub fn write_scalar( + &mut self, + range: AllocRange, + val: ScalarMaybeUninit<Tag>, + ) -> InterpResult<'tcx> { + Ok(self + .alloc + .write_scalar(&self.tcx, self.range.subrange(range), val) + .map_err(|e| e.to_interp_error(self.alloc_id))?) + } + + pub fn write_ptr_sized( + &mut self, + offset: Size, + val: ScalarMaybeUninit<Tag>, + ) -> InterpResult<'tcx> { + self.write_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size), val) + } +} + +impl<'tcx, 'a, Tag: Copy, Extra> AllocRef<'a, 'tcx, Tag, Extra> { + pub fn read_scalar(&self, range: AllocRange) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { + Ok(self + .alloc + .read_scalar(&self.tcx, self.range.subrange(range)) + .map_err(|e| e.to_interp_error(self.alloc_id))?) + } + + pub fn read_ptr_sized(&self, offset: Size) -> InterpResult<'tcx, ScalarMaybeUninit<Tag>> { + self.read_scalar(alloc_range(offset, self.tcx.data_layout().pointer_size)) + } + + pub fn check_bytes(&self, range: AllocRange, allow_uninit_and_ptr: bool) -> InterpResult<'tcx> { + Ok(self + .alloc + .check_bytes(&self.tcx, self.range.subrange(range), allow_uninit_and_ptr) + .map_err(|e| e.to_interp_error(self.alloc_id))?) + } +} + impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { /// Reads the given number of bytes from memory. Returns them as a slice. /// /// Performs appropriate bounds checks. - pub fn read_bytes(&self, ptr: Scalar<M::PointerTag>, size: Size) -> InterpResult<'tcx, &[u8]> { - let ptr = match self.check_ptr_access(ptr, size, Align::from_bytes(1).unwrap())? { - Some(ptr) => ptr, + pub fn read_bytes(&self, sptr: Scalar<M::PointerTag>, size: Size) -> InterpResult<'tcx, &[u8]> { + let alloc_ref = match self.get(sptr, size, Align::ONE)? { + Some(a) => a, None => return Ok(&[]), // zero-sized access }; - self.get_raw(ptr.alloc_id)?.get_bytes(self, ptr, size) + // Side-step AllocRef and directly access the underlying bytes more efficiently. + // (We are staying inside the bounds here so all is good.) + Ok(alloc_ref + .alloc + .get_bytes(&alloc_ref.tcx, alloc_ref.range) + .map_err(|e| e.to_interp_error(alloc_ref.alloc_id))?) } /// Writes the given stream of bytes into memory. @@ -809,14 +963,17 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { /// Performs appropriate bounds checks. pub fn write_bytes( &mut self, - ptr: Scalar<M::PointerTag>, + sptr: Scalar<M::PointerTag>, src: impl IntoIterator<Item = u8>, ) -> InterpResult<'tcx> { let mut src = src.into_iter(); - let size = Size::from_bytes(src.size_hint().0); - // `write_bytes` checks that this lower bound `size` matches the upper bound and reality. - let ptr = match self.check_ptr_access(ptr, size, Align::from_bytes(1).unwrap())? { - Some(ptr) => ptr, + let (lower, upper) = src.size_hint(); + let len = upper.expect("can only write bounded iterators"); + assert_eq!(lower, len, "can only write iterators with a precise length"); + + let size = Size::from_bytes(len); + let alloc_ref = match self.get_mut(sptr, size, Align::ONE)? { + Some(alloc_ref) => alloc_ref, None => { // zero-sized access assert_matches!( @@ -827,56 +984,88 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { return Ok(()); } }; - let tcx = self.tcx; - self.get_raw_mut(ptr.alloc_id)?.write_bytes(&tcx, ptr, src) + + // Side-step AllocRef and directly access the underlying bytes more efficiently. + // (We are staying inside the bounds here so all is good.) + let bytes = alloc_ref.alloc.get_bytes_mut(&alloc_ref.tcx, alloc_ref.range); + // `zip` would stop when the first iterator ends; we want to definitely + // cover all of `bytes`. + for dest in bytes { + *dest = src.next().expect("iterator was shorter than it said it would be"); + } + assert_matches!(src.next(), None, "iterator was longer than it said it would be"); + Ok(()) } - /// Expects the caller to have checked bounds and alignment. pub fn copy( &mut self, - src: Pointer<M::PointerTag>, - dest: Pointer<M::PointerTag>, + src: Scalar<M::PointerTag>, + src_align: Align, + dest: Scalar<M::PointerTag>, + dest_align: Align, size: Size, nonoverlapping: bool, ) -> InterpResult<'tcx> { - self.copy_repeatedly(src, dest, size, 1, nonoverlapping) + self.copy_repeatedly(src, src_align, dest, dest_align, size, 1, nonoverlapping) } - /// Expects the caller to have checked bounds and alignment. pub fn copy_repeatedly( &mut self, - src: Pointer<M::PointerTag>, - dest: Pointer<M::PointerTag>, + src: Scalar<M::PointerTag>, + src_align: Align, + dest: Scalar<M::PointerTag>, + dest_align: Align, size: Size, - length: u64, + num_copies: u64, nonoverlapping: bool, ) -> InterpResult<'tcx> { + let tcx = self.tcx; + // We need to do our own bounds-checks. + let src = self.check_ptr_access(src, size, src_align)?; + let dest = self.check_ptr_access(dest, size * num_copies, dest_align)?; // `Size` multiplication + + // FIXME: we look up both allocations twice here, once ebfore for the `check_ptr_access` + // and once below to get the underlying `&[mut] Allocation`. + + // Source alloc preparations and access hooks. + let src = match src { + None => return Ok(()), // Zero-sized *source*, that means dst is also zero-sized and we have nothing to do. + Some(src_ptr) => src_ptr, + }; + let src_alloc = self.get_raw(src.alloc_id)?; + M::memory_read(&self.extra, &src_alloc.extra, src, size)?; + // We need the `dest` ptr for the next operation, so we get it now. + // We already did the source checks and called the hooks so we are good to return early. + let dest = match dest { + None => return Ok(()), // Zero-sized *destiantion*. + Some(dest_ptr) => dest_ptr, + }; + // first copy the relocations to a temporary buffer, because // `get_bytes_mut` will clear the relocations, which is correct, // since we don't want to keep any relocations at the target. // (`get_bytes_with_uninit_and_ptr` below checks that there are no // relocations overlapping the edges; those would not be handled correctly). - let relocations = - self.get_raw(src.alloc_id)?.prepare_relocation_copy(self, src, size, dest, length); - - let tcx = self.tcx; - - // This checks relocation edges on the src. - let src_bytes = - self.get_raw(src.alloc_id)?.get_bytes_with_uninit_and_ptr(&tcx, src, size)?.as_ptr(); - let dest_bytes = - self.get_raw_mut(dest.alloc_id)?.get_bytes_mut(&tcx, dest, size * length)?; // `Size` multiplication - - // If `dest_bytes` is empty we just optimize to not run anything for zsts. - // See #67539 - if dest_bytes.is_empty() { - return Ok(()); - } - - let dest_bytes = dest_bytes.as_mut_ptr(); - + let relocations = src_alloc.prepare_relocation_copy( + self, + alloc_range(src.offset, size), + dest.offset, + num_copies, + ); // Prepare a copy of the initialization mask. - let compressed = self.get_raw(src.alloc_id)?.compress_uninit_range(src, size); + let compressed = src_alloc.compress_uninit_range(src, size); + // This checks relocation edges on the src. + let src_bytes = src_alloc + .get_bytes_with_uninit_and_ptr(&tcx, alloc_range(src.offset, size)) + .map_err(|e| e.to_interp_error(src.alloc_id))? + .as_ptr(); // raw ptr, so we can also get a ptr to the destination allocation + + // Destination alloc preparations and access hooks. + let (dest_alloc, extra) = self.get_raw_mut(dest.alloc_id)?; + M::memory_written(extra, &mut dest_alloc.extra, dest, size * num_copies)?; + let dest_bytes = dest_alloc + .get_bytes_mut_ptr(&tcx, alloc_range(dest.offset, size * num_copies)) + .as_mut_ptr(); if compressed.no_bytes_init() { // Fast path: If all bytes are `uninit` then there is nothing to copy. The target range @@ -885,8 +1074,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // This also avoids writing to the target bytes so that the backing allocation is never // touched if the bytes stay uninitialized for the whole interpreter execution. On contemporary // operating system this can avoid physically allocating the page. - let dest_alloc = self.get_raw_mut(dest.alloc_id)?; - dest_alloc.mark_init(dest, size * length, false); // `Size` multiplication + dest_alloc.mark_init(alloc_range(dest.offset, size * num_copies), false); // `Size` multiplication dest_alloc.mark_relocation_range(relocations); return Ok(()); } @@ -907,7 +1095,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } } - for i in 0..length { + for i in 0..num_copies { ptr::copy( src_bytes, dest_bytes.add((size * i).bytes_usize()), // `Size` multiplication @@ -915,7 +1103,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { ); } } else { - for i in 0..length { + for i in 0..num_copies { ptr::copy_nonoverlapping( src_bytes, dest_bytes.add((size * i).bytes_usize()), // `Size` multiplication @@ -925,16 +1113,10 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { } } - // now fill in all the data - self.get_raw_mut(dest.alloc_id)?.mark_compressed_init_range( - &compressed, - dest, - size, - length, - ); - + // now fill in all the "init" data + dest_alloc.mark_compressed_init_range(&compressed, dest, size, num_copies); // copy the relocations to the destination - self.get_raw_mut(dest.alloc_id)?.mark_relocation_range(relocations); + dest_alloc.mark_relocation_range(relocations); Ok(()) } diff --git a/compiler/rustc_mir/src/interpret/mod.rs b/compiler/rustc_mir/src/interpret/mod.rs index a29ef117ace..2b9fe565997 100644 --- a/compiler/rustc_mir/src/interpret/mod.rs +++ b/compiler/rustc_mir/src/interpret/mod.rs @@ -18,10 +18,12 @@ mod visitor; pub use rustc_middle::mir::interpret::*; // have all the `interpret` symbols in one place: here -pub use self::eval_context::{Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup}; +pub use self::eval_context::{ + Frame, FrameInfo, InterpCx, LocalState, LocalValue, StackPopCleanup, StackPopUnwind, +}; pub use self::intern::{intern_const_alloc_recursive, InternKind}; pub use self::machine::{compile_time_machine, AllocMap, Machine, MayLeak, StackPopJump}; -pub use self::memory::{AllocCheck, FnVal, Memory, MemoryKind}; +pub use self::memory::{AllocCheck, AllocRef, AllocRefMut, FnVal, Memory, MemoryKind}; pub use self::operand::{ImmTy, Immediate, OpTy, Operand}; pub use self::place::{MPlaceTy, MemPlace, MemPlaceMeta, Place, PlaceTy}; pub use self::validity::{CtfeValidationMode, RefTracking}; diff --git a/compiler/rustc_mir/src/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs index e5bc9320260..06432a8b902 100644 --- a/compiler/rustc_mir/src/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -15,8 +15,8 @@ use rustc_target::abi::{Abi, HasDataLayout, LayoutOf, Size, TagEncoding}; use rustc_target::abi::{VariantIdx, Variants}; use super::{ - from_known_layout, mir_assign_valid_types, ConstValue, GlobalId, InterpCx, InterpResult, - MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, + alloc_range, from_known_layout, mir_assign_valid_types, ConstValue, GlobalId, InterpCx, + InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, }; /// An `Immediate` represents a single immediate self-contained Rust value. @@ -249,19 +249,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { return Ok(None); } - let ptr = match self - .check_mplace_access(mplace, None) - .expect("places should be checked on creation") - { + let alloc = match self.get_alloc(mplace)? { Some(ptr) => ptr, None => { - if let Scalar::Ptr(ptr) = mplace.ptr { - // We may be reading from a static. - // In order to ensure that `static FOO: Type = FOO;` causes a cycle error - // instead of magically pulling *any* ZST value from the ether, we need to - // actually access the referenced allocation. - self.memory.get_raw(ptr.alloc_id)?; - } return Ok(Some(ImmTy { // zero-sized type imm: Scalar::ZST.into(), @@ -270,11 +260,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } }; - let alloc = self.memory.get_raw(ptr.alloc_id)?; - match mplace.layout.abi { Abi::Scalar(..) => { - let scalar = alloc.read_scalar(self, ptr, mplace.layout.size)?; + let scalar = alloc.read_scalar(alloc_range(Size::ZERO, mplace.layout.size))?; Ok(Some(ImmTy { imm: scalar.into(), layout: mplace.layout })) } Abi::ScalarPair(ref a, ref b) => { @@ -283,12 +271,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // which `ptr.offset(b_offset)` cannot possibly fail to satisfy. let (a, b) = (&a.value, &b.value); let (a_size, b_size) = (a.size(self), b.size(self)); - let a_ptr = ptr; let b_offset = a_size.align_to(b.align(self).abi); assert!(b_offset.bytes() > 0); // we later use the offset to tell apart the fields - let b_ptr = ptr.offset(b_offset, self)?; - let a_val = alloc.read_scalar(self, a_ptr, a_size)?; - let b_val = alloc.read_scalar(self, b_ptr, b_size)?; + let a_val = alloc.read_scalar(alloc_range(Size::ZERO, a_size))?; + let b_val = alloc.read_scalar(alloc_range(b_offset, b_size))?; Ok(Some(ImmTy { imm: Immediate::ScalarPair(a_val, b_val), layout: mplace.layout })) } _ => Ok(None), diff --git a/compiler/rustc_mir/src/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs index d7c11aee21f..4c53510ed00 100644 --- a/compiler/rustc_mir/src/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -6,6 +6,7 @@ use std::convert::TryFrom; use std::fmt::Debug; use std::hash::Hash; +use rustc_ast::Mutability; use rustc_macros::HashStable; use rustc_middle::mir; use rustc_middle::ty::layout::{PrimitiveExt, TyAndLayout}; @@ -14,8 +15,8 @@ use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding}; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants}; use super::{ - mir_assign_valid_types, AllocId, AllocMap, Allocation, AllocationExtra, ConstAlloc, ImmTy, - Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, + alloc_range, mir_assign_valid_types, AllocRef, AllocRefMut, ConstAlloc, ImmTy, Immediate, + InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, PointerArithmetic, Scalar, ScalarMaybeUninit, }; @@ -291,9 +292,6 @@ where // FIXME: Working around https://github.com/rust-lang/rust/issues/54385 Tag: Debug + Copy + Eq + Hash + 'static, M: Machine<'mir, 'tcx, PointerTag = Tag>, - // FIXME: Working around https://github.com/rust-lang/rust/issues/24159 - M::MemoryMap: AllocMap<AllocId, (MemoryKind<M::MemoryKind>, Allocation<Tag, M::AllocExtra>)>, - M::AllocExtra: AllocationExtra<Tag>, { /// Take a value, which represents a (thin or wide) reference, and make it a place. /// Alignment is just based on the type. This is the inverse of `MemPlace::to_ref()`. @@ -339,24 +337,26 @@ where self.mplace_access_checked(place, None) } - /// Check if the given place is good for memory access with the given - /// size, falling back to the layout's size if `None` (in the latter case, - /// this must be a statically sized type). - /// - /// On success, returns `None` for zero-sized accesses (where nothing else is - /// left to do) and a `Pointer` to use for the actual access otherwise. #[inline] - pub(super) fn check_mplace_access( + pub(super) fn get_alloc( &self, place: &MPlaceTy<'tcx, M::PointerTag>, - size: Option<Size>, - ) -> InterpResult<'tcx, Option<Pointer<M::PointerTag>>> { - let size = size.unwrap_or_else(|| { - assert!(!place.layout.is_unsized()); - assert!(!place.meta.has_meta()); - place.layout.size - }); - self.memory.check_ptr_access(place.ptr, size, place.align) + ) -> InterpResult<'tcx, Option<AllocRef<'_, 'tcx, M::PointerTag, M::AllocExtra>>> { + assert!(!place.layout.is_unsized()); + assert!(!place.meta.has_meta()); + let size = place.layout.size; + self.memory.get(place.ptr, size, place.align) + } + + #[inline] + pub(super) fn get_alloc_mut( + &mut self, + place: &MPlaceTy<'tcx, M::PointerTag>, + ) -> InterpResult<'tcx, Option<AllocRefMut<'_, 'tcx, M::PointerTag, M::AllocExtra>>> { + assert!(!place.layout.is_unsized()); + assert!(!place.meta.has_meta()); + let size = place.layout.size; + self.memory.get_mut(place.ptr, size, place.align) } /// Return the "access-checked" version of this `MPlace`, where for non-ZST @@ -373,10 +373,11 @@ where .size_and_align_of_mplace(&place)? .unwrap_or((place.layout.size, place.layout.align.abi)); assert!(place.mplace.align <= align, "dynamic alignment less strict than static one?"); - // Check (stricter) dynamic alignment, unless forced otherwise. - place.mplace.align = force_align.unwrap_or(align); + let align = force_align.unwrap_or(align); + // Record new (stricter, unless forced) alignment requirement in place. + place.mplace.align = align; // When dereferencing a pointer, it must be non-null, aligned, and live. - if let Some(ptr) = self.check_mplace_access(&place, Some(size))? { + if let Some(ptr) = self.memory.check_ptr_access(place.ptr, size, align)? { place.mplace.ptr = ptr.into(); } Ok(place) @@ -786,12 +787,12 @@ where // wrong type. // Invalid places are a thing: the return place of a diverging function - let ptr = match self.check_mplace_access(dest, None)? { - Some(ptr) => ptr, + let tcx = *self.tcx; + let mut alloc = match self.get_alloc_mut(dest)? { + Some(a) => a, None => return Ok(()), // zero-sized access }; - let tcx = *self.tcx; // FIXME: We should check that there are dest.layout.size many bytes available in // memory. The code below is not sufficient, with enough padding it might not // cover all the bytes! @@ -805,12 +806,7 @@ where dest.layout ), } - self.memory.get_raw_mut(ptr.alloc_id)?.write_scalar( - &tcx, - ptr, - scalar, - dest.layout.size, - ) + alloc.write_scalar(alloc_range(Size::ZERO, dest.layout.size), scalar) } Immediate::ScalarPair(a_val, b_val) => { // We checked `ptr_align` above, so all fields will have the alignment they need. @@ -824,16 +820,15 @@ where dest.layout ), }; - let (a_size, b_size) = (a.size(self), b.size(self)); - let b_offset = a_size.align_to(b.align(self).abi); - let b_ptr = ptr.offset(b_offset, self)?; + let (a_size, b_size) = (a.size(&tcx), b.size(&tcx)); + let b_offset = a_size.align_to(b.align(&tcx).abi); // It is tempting to verify `b_offset` against `layout.fields.offset(1)`, // but that does not work: We could be a newtype around a pair, then the // fields do not match the `ScalarPair` components. - self.memory.get_raw_mut(ptr.alloc_id)?.write_scalar(&tcx, ptr, a_val, a_size)?; - self.memory.get_raw_mut(b_ptr.alloc_id)?.write_scalar(&tcx, b_ptr, b_val, b_size) + alloc.write_scalar(alloc_range(Size::ZERO, a_size), a_val)?; + alloc.write_scalar(alloc_range(b_offset, b_size), b_val) } } } @@ -902,19 +897,8 @@ where }); assert_eq!(src.meta, dest.meta, "Can only copy between equally-sized instances"); - let src = self - .check_mplace_access(&src, Some(size)) - .expect("places should be checked on creation"); - let dest = self - .check_mplace_access(&dest, Some(size)) - .expect("places should be checked on creation"); - let (src_ptr, dest_ptr) = match (src, dest) { - (Some(src_ptr), Some(dest_ptr)) => (src_ptr, dest_ptr), - (None, None) => return Ok(()), // zero-sized copy - _ => bug!("The pointers should both be Some or both None"), - }; - - self.memory.copy(src_ptr, dest_ptr, size, /*nonoverlapping*/ true) + self.memory + .copy(src.ptr, src.align, dest.ptr, dest.align, size, /*nonoverlapping*/ true) } /// Copies the data from an operand to a place. The layouts may disagree, but they must @@ -1039,21 +1023,23 @@ where MPlaceTy::from_aligned_ptr(ptr, layout) } - /// Returns a wide MPlace. + /// Returns a wide MPlace of type `&'static [mut] str` to a new 1-aligned allocation. pub fn allocate_str( &mut self, str: &str, kind: MemoryKind<M::MemoryKind>, + mutbl: Mutability, ) -> MPlaceTy<'tcx, M::PointerTag> { - let ptr = self.memory.allocate_bytes(str.as_bytes(), kind); + let ptr = self.memory.allocate_bytes(str.as_bytes(), Align::ONE, kind, mutbl); let meta = Scalar::from_machine_usize(u64::try_from(str.len()).unwrap(), self); - let mplace = MemPlace { - ptr: ptr.into(), - align: Align::from_bytes(1).unwrap(), - meta: MemPlaceMeta::Meta(meta), - }; + let mplace = + MemPlace { ptr: ptr.into(), align: Align::ONE, meta: MemPlaceMeta::Meta(meta) }; - let layout = self.layout_of(self.tcx.mk_static_str()).unwrap(); + let ty = self.tcx.mk_ref( + self.tcx.lifetimes.re_static, + ty::TypeAndMut { ty: self.tcx.types.str_, mutbl }, + ); + let layout = self.layout_of(ty).unwrap(); MPlaceTy { mplace, layout } } diff --git a/compiler/rustc_mir/src/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs index 5a10ffe6d61..129dd8f8e01 100644 --- a/compiler/rustc_mir/src/interpret/step.rs +++ b/compiler/rustc_mir/src/interpret/step.rs @@ -222,28 +222,34 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } Repeat(ref operand, _) => { - let op = self.eval_operand(operand, None)?; + let src = self.eval_operand(operand, None)?; + assert!(!src.layout.is_unsized()); let dest = self.force_allocation(&dest)?; let length = dest.len(self)?; - if let Some(first_ptr) = self.check_mplace_access(&dest, None)? { - // Write the first. + if length == 0 { + // Nothing to copy... but let's still make sure that `dest` as a place is valid. + self.get_alloc_mut(&dest)?; + } else { + // Write the src to the first element. let first = self.mplace_field(&dest, 0)?; - self.copy_op(&op, &first.into())?; - - if length > 1 { - let elem_size = first.layout.size; - // Copy the rest. This is performance-sensitive code - // for big static/const arrays! - let rest_ptr = first_ptr.offset(elem_size, self)?; - self.memory.copy_repeatedly( - first_ptr, - rest_ptr, - elem_size, - length - 1, - /*nonoverlapping:*/ true, - )?; - } + self.copy_op(&src, &first.into())?; + + // This is performance-sensitive code for big static/const arrays! So we + // avoid writing each operand individually and instead just make many copies + // of the first element. + let elem_size = first.layout.size; + let first_ptr = first.ptr; + let rest_ptr = first_ptr.ptr_offset(elem_size, self)?; + self.memory.copy_repeatedly( + first_ptr, + first.align, + rest_ptr, + first.align, + elem_size, + length - 1, + /*nonoverlapping:*/ true, + )?; } } diff --git a/compiler/rustc_mir/src/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs index a7fcb41f74a..a5bdeb55e78 100644 --- a/compiler/rustc_mir/src/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -1,7 +1,8 @@ use std::borrow::Cow; use std::convert::TryFrom; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::ty::layout::{self, TyAndLayout}; use rustc_middle::ty::Instance; use rustc_middle::{ mir, @@ -12,9 +13,19 @@ use rustc_target::spec::abi::Abi; use super::{ FnVal, ImmTy, InterpCx, InterpResult, MPlaceTy, Machine, OpTy, PlaceTy, StackPopCleanup, + StackPopUnwind, }; impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { + fn fn_can_unwind(&self, attrs: CodegenFnAttrFlags, abi: Abi) -> bool { + layout::fn_can_unwind( + self.tcx.sess.panic_strategy(), + attrs, + layout::conv_from_spec_abi(*self.tcx, abi), + abi, + ) + } + pub(super) fn eval_terminator( &mut self, terminator: &mir::Terminator<'tcx>, @@ -58,12 +69,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let old_stack = self.frame_idx(); let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; - let (fn_val, abi) = match *func.layout.ty.kind() { + let (fn_val, abi, caller_can_unwind) = match *func.layout.ty.kind() { ty::FnPtr(sig) => { let caller_abi = sig.abi(); let fn_ptr = self.read_scalar(&func)?.check_init()?; let fn_val = self.memory.get_fn(fn_ptr)?; - (fn_val, caller_abi) + ( + fn_val, + caller_abi, + self.fn_can_unwind(layout::fn_ptr_codegen_fn_attr_flags(), caller_abi), + ) } ty::FnDef(def_id, substs) => { let sig = func.layout.ty.fn_sig(*self.tcx); @@ -72,6 +87,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?, ), sig.abi(), + self.fn_can_unwind(self.tcx.codegen_fn_attrs(def_id).flags, sig.abi()), ) } _ => span_bug!( @@ -89,7 +105,17 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } None => None, }; - self.eval_fn_call(fn_val, abi, &args[..], ret, *cleanup)?; + self.eval_fn_call( + fn_val, + abi, + &args[..], + ret, + match (cleanup, caller_can_unwind) { + (Some(cleanup), true) => StackPopUnwind::Cleanup(*cleanup), + (None, true) => StackPopUnwind::Skip, + (_, false) => StackPopUnwind::NotAllowed, + }, + )?; // Sanity-check that `eval_fn_call` either pushed a new frame or // did a jump to another block. if self.frame_idx() == old_stack && self.frame().loc == old_loc { @@ -219,7 +245,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { caller_abi: Abi, args: &[OpTy<'tcx, M::PointerTag>], ret: Option<(&PlaceTy<'tcx, M::PointerTag>, mir::BasicBlock)>, - unwind: Option<mir::BasicBlock>, + mut unwind: StackPopUnwind, ) -> InterpResult<'tcx> { trace!("eval_fn_call: {:#?}", fn_val); @@ -230,14 +256,15 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } }; + let get_abi = |this: &Self, instance_ty: Ty<'tcx>| match instance_ty.kind() { + ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(), + ty::Closure(..) => Abi::RustCall, + ty::Generator(..) => Abi::Rust, + _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty), + }; + // ABI check - let check_abi = |this: &Self, instance_ty: Ty<'tcx>| -> InterpResult<'tcx> { - let callee_abi = match instance_ty.kind() { - ty::FnDef(..) => instance_ty.fn_sig(*this.tcx).abi(), - ty::Closure(..) => Abi::RustCall, - ty::Generator(..) => Abi::Rust, - _ => span_bug!(this.cur_span(), "unexpected callee ty: {:?}", instance_ty), - }; + let check_abi = |callee_abi: Abi| -> InterpResult<'tcx> { let normalize_abi = |abi| match abi { Abi::Rust | Abi::RustCall | Abi::RustIntrinsic | Abi::PlatformIntrinsic => // These are all the same ABI, really. @@ -258,7 +285,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { match instance.def { ty::InstanceDef::Intrinsic(..) => { - check_abi(self, instance.ty(*self.tcx, self.param_env))?; + if M::enforce_abi(self) { + check_abi(get_abi(self, instance.ty(*self.tcx, self.param_env)))?; + } assert!(caller_abi == Abi::RustIntrinsic || caller_abi == Abi::PlatformIntrinsic); M::call_intrinsic(self, instance, args, ret, unwind) } @@ -279,7 +308,20 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Check against the ABI of the MIR body we are calling (not the ABI of `instance`; // these can differ when `find_mir_or_eval_fn` does something clever like resolve // exported symbol names). - check_abi(self, self.tcx.type_of(body.source.def_id()))?; + let callee_def_id = body.source.def_id(); + let callee_abi = get_abi(self, self.tcx.type_of(callee_def_id)); + + if M::enforce_abi(self) { + check_abi(callee_abi)?; + } + + if !matches!(unwind, StackPopUnwind::NotAllowed) + && !self + .fn_can_unwind(self.tcx.codegen_fn_attrs(callee_def_id).flags, callee_abi) + { + // The callee cannot unwind. + unwind = StackPopUnwind::NotAllowed; + } self.push_stack_frame( instance, @@ -469,7 +511,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Abi::Rust, &[arg.into()], Some((&dest.into(), target)), - unwind, + match unwind { + Some(cleanup) => StackPopUnwind::Cleanup(cleanup), + None => StackPopUnwind::Skip, + }, ) } } diff --git a/compiler/rustc_mir/src/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs index 50603bdd45b..11f8d388820 100644 --- a/compiler/rustc_mir/src/interpret/traits.rs +++ b/compiler/rustc_mir/src/interpret/traits.rs @@ -62,32 +62,32 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let drop = Instance::resolve_drop_in_place(tcx, ty); let drop = self.memory.create_fn_alloc(FnVal::Instance(drop)); + // Prepare the fn ptrs we will write into the vtable later. + let fn_ptrs = methods + .iter() + .enumerate() // remember the original position + .filter_map(|(i, method)| { + if let Some((def_id, substs)) = method { Some((i, def_id, substs)) } else { None } + }) + .map(|(i, def_id, substs)| { + let instance = + ty::Instance::resolve_for_vtable(tcx, self.param_env, *def_id, substs) + .ok_or_else(|| err_inval!(TooGeneric))?; + Ok((i, self.memory.create_fn_alloc(FnVal::Instance(instance)))) + }) + .collect::<InterpResult<'tcx, Vec<(usize, Pointer<M::PointerTag>)>>>()?; + // No need to do any alignment checks on the memory accesses below, because we know the // allocation is correctly aligned as we created it above. Also we're only offsetting by // multiples of `ptr_align`, which means that it will stay aligned to `ptr_align`. - let vtable_alloc = self.memory.get_raw_mut(vtable.alloc_id)?; - vtable_alloc.write_ptr_sized(&tcx, vtable, drop.into())?; - - let size_ptr = vtable.offset(ptr_size, &tcx)?; - vtable_alloc.write_ptr_sized(&tcx, size_ptr, Scalar::from_uint(size, ptr_size).into())?; - let align_ptr = vtable.offset(ptr_size * 2, &tcx)?; - vtable_alloc.write_ptr_sized(&tcx, align_ptr, Scalar::from_uint(align, ptr_size).into())?; - - for (i, method) in methods.iter().enumerate() { - if let Some((def_id, substs)) = *method { - // resolve for vtable: insert shims where needed - let instance = - ty::Instance::resolve_for_vtable(tcx, self.param_env, def_id, substs) - .ok_or_else(|| err_inval!(TooGeneric))?; - let fn_ptr = self.memory.create_fn_alloc(FnVal::Instance(instance)); - // We cannot use `vtable_allic` as we are creating fn ptrs in this loop. - let method_ptr = vtable.offset(ptr_size * (3 + i as u64), &tcx)?; - self.memory.get_raw_mut(vtable.alloc_id)?.write_ptr_sized( - &tcx, - method_ptr, - fn_ptr.into(), - )?; - } + let mut vtable_alloc = + self.memory.get_mut(vtable.into(), vtable_size, ptr_align)?.expect("not a ZST"); + vtable_alloc.write_ptr_sized(ptr_size * 0, drop.into())?; + vtable_alloc.write_ptr_sized(ptr_size * 1, Scalar::from_uint(size, ptr_size).into())?; + vtable_alloc.write_ptr_sized(ptr_size * 2, Scalar::from_uint(align, ptr_size).into())?; + + for (i, fn_ptr) in fn_ptrs.into_iter() { + vtable_alloc.write_ptr_sized(ptr_size * (3 + i as u64), fn_ptr.into())?; } M::after_static_mem_initialized(self, vtable, vtable_size)?; @@ -111,13 +111,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let vtable_slot = vtable.ptr_offset(ptr_size * idx.checked_add(3).unwrap(), self)?; let vtable_slot = self .memory - .check_ptr_access(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)? + .get(vtable_slot, ptr_size, self.tcx.data_layout.pointer_align.abi)? .expect("cannot be a ZST"); - let fn_ptr = self - .memory - .get_raw(vtable_slot.alloc_id)? - .read_ptr_sized(self, vtable_slot)? - .check_init()?; + let fn_ptr = vtable_slot.read_ptr_sized(Size::ZERO)?.check_init()?; self.memory.get_fn(fn_ptr) } @@ -129,14 +125,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // We don't care about the pointee type; we just want a pointer. let vtable = self .memory - .check_ptr_access( - vtable, - self.tcx.data_layout.pointer_size, - self.tcx.data_layout.pointer_align.abi, - )? + .get(vtable, self.tcx.data_layout.pointer_size, self.tcx.data_layout.pointer_align.abi)? .expect("cannot be a ZST"); - let drop_fn = - self.memory.get_raw(vtable.alloc_id)?.read_ptr_sized(self, vtable)?.check_init()?; + let drop_fn = vtable.read_ptr_sized(Size::ZERO)?.check_init()?; // We *need* an instance here, no other kind of function value, to be able // to determine the type. let drop_instance = self.memory.get_fn(drop_fn)?.as_instance()?; @@ -161,13 +152,11 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // the size, and the align (which we read below). let vtable = self .memory - .check_ptr_access(vtable, 3 * pointer_size, self.tcx.data_layout.pointer_align.abi)? + .get(vtable, 3 * pointer_size, self.tcx.data_layout.pointer_align.abi)? .expect("cannot be a ZST"); - let alloc = self.memory.get_raw(vtable.alloc_id)?; - let size = alloc.read_ptr_sized(self, vtable.offset(pointer_size, self)?)?.check_init()?; + let size = vtable.read_ptr_sized(pointer_size)?.check_init()?; let size = u64::try_from(self.force_bits(size, pointer_size)?).unwrap(); - let align = - alloc.read_ptr_sized(self, vtable.offset(pointer_size * 2, self)?)?.check_init()?; + let align = vtable.read_ptr_sized(pointer_size * 2)?.check_init()?; let align = u64::try_from(self.force_bits(align, pointer_size)?).unwrap(); if size >= self.tcx.data_layout.obj_size_bound() { diff --git a/compiler/rustc_mir/src/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs index 83b0d0528f7..fb165a991bc 100644 --- a/compiler/rustc_mir/src/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -15,13 +15,13 @@ use rustc_middle::mir::interpret::InterpError; use rustc_middle::ty; use rustc_middle::ty::layout::TyAndLayout; use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::{Abi, LayoutOf, Scalar, Size, VariantIdx, Variants}; +use rustc_target::abi::{Abi, LayoutOf, Scalar as ScalarAbi, Size, VariantIdx, Variants}; use std::hash::Hash; use super::{ - CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, MemPlaceMeta, OpTy, - ScalarMaybeUninit, ValueVisitor, + alloc_range, CheckInAllocMsg, GlobalAlloc, InterpCx, InterpResult, MPlaceTy, Machine, + MemPlaceMeta, OpTy, Scalar, ScalarMaybeUninit, ValueVisitor, }; macro_rules! throw_validation_failure { @@ -329,7 +329,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' self.ecx.memory.check_ptr_access_align( vtable, 3 * self.ecx.tcx.data_layout.pointer_size, // drop, size, align - Some(self.ecx.tcx.data_layout.pointer_align.abi), + self.ecx.tcx.data_layout.pointer_align.abi, CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message ), self.path, @@ -411,11 +411,11 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' // alignment should take attributes into account). .unwrap_or_else(|| (place.layout.size, place.layout.align.abi)); // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. - let ptr: Option<_> = try_validation!( + try_validation!( self.ecx.memory.check_ptr_access_align( place.ptr, size, - Some(align), + align, CheckInAllocMsg::InboundsTest, // will anyway be replaced by validity message ), self.path, @@ -441,9 +441,18 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' ); // Recursive checking if let Some(ref mut ref_tracking) = self.ref_tracking { - if let Some(ptr) = ptr { + // Proceed recursively even for ZST, no reason to skip them! + // `!` is a ZST and we want to validate it. + // Normalize before handing `place` to tracking because that will + // check for duplicates. + let place = if size.bytes() > 0 { + self.ecx.force_mplace_ptr(place).expect("we already bounds-checked") + } else { + place + }; + // Skip validation entirely for some external statics + if let Scalar::Ptr(ptr) = place.ptr { // not a ZST - // Skip validation entirely for some external statics let alloc_kind = self.ecx.tcx.get_global_alloc(ptr.alloc_id); if let Some(GlobalAlloc::Static(did)) = alloc_kind { assert!(!self.ecx.tcx.is_thread_local_static(did)); @@ -473,15 +482,6 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' return Ok(()); } } - // Proceed recursively even for ZST, no reason to skip them! - // `!` is a ZST and we want to validate it. - // Normalize before handing `place` to tracking because that will - // check for duplicates. - let place = if size.bytes() > 0 { - self.ecx.force_mplace_ptr(place).expect("we already bounds-checked") - } else { - place - }; let path = &self.path; ref_tracking.track(place, || { // We need to clone the path anyway, make sure it gets created @@ -638,7 +638,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' fn visit_scalar( &mut self, op: &OpTy<'tcx, M::PointerTag>, - scalar_layout: &Scalar, + scalar_layout: &ScalarAbi, ) -> InterpResult<'tcx> { let value = self.read_scalar(op)?; let valid_range = &scalar_layout.valid_range; @@ -851,16 +851,10 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> let mplace = op.assert_mem_place(self.ecx); // This is the length of the array/slice. let len = mplace.len(self.ecx)?; - // Zero length slices have nothing to be checked. - if len == 0 { - return Ok(()); - } // This is the element type size. let layout = self.ecx.layout_of(tys)?; // This is the size in bytes of the whole array. (This checks for overflow.) let size = layout.size * len; - // Size is not 0, get a pointer. - let ptr = self.ecx.force_ptr(mplace.ptr)?; // Optimization: we just check the entire range at once. // NOTE: Keep this in sync with the handling of integer and float @@ -872,10 +866,16 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // to reject those pointers, we just do not have the machinery to // talk about parts of a pointer. // We also accept uninit, for consistency with the slow path. - match self.ecx.memory.get_raw(ptr.alloc_id)?.check_bytes( - self.ecx, - ptr, - size, + let alloc = match self.ecx.memory.get(mplace.ptr, size, mplace.align)? { + Some(a) => a, + None => { + // Size 0, nothing more to check. + return Ok(()); + } + }; + + match alloc.check_bytes( + alloc_range(Size::ZERO, size), /*allow_uninit_and_ptr*/ self.ctfe_mode.is_none(), ) { // In the happy case, we needn't check anything else. @@ -885,12 +885,12 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // For some errors we might be able to provide extra information. // (This custom logic does not fit the `try_validation!` macro.) match err.kind() { - err_ub!(InvalidUninitBytes(Some(access))) => { + err_ub!(InvalidUninitBytes(Some((_alloc_id, access)))) => { // Some byte was uninitialized, determine which // element that byte belongs to so we can // provide an index. let i = usize::try_from( - access.uninit_ptr.offset.bytes() / layout.size.bytes(), + access.uninit_offset.bytes() / layout.size.bytes(), ) .unwrap(); self.path.push(PathElem::ArrayElem(i)); diff --git a/compiler/rustc_mir/src/lib.rs b/compiler/rustc_mir/src/lib.rs index 783aa9465c3..12a36976f1d 100644 --- a/compiler/rustc_mir/src/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -12,22 +12,20 @@ Rust MIR: a lowered representation of Rust. #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(exact_size_is_empty)] -#![feature(exhaustive_patterns)] #![feature(iter_zip)] #![feature(never_type)] #![feature(map_try_insert)] #![feature(min_specialization)] +#![feature(slice_ptr_get)] #![feature(trusted_len)] #![feature(try_blocks)] #![feature(associated_type_defaults)] #![feature(stmt_expr_attributes)] #![feature(trait_alias)] #![feature(option_get_or_insert_default)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(once_cell)] #![feature(control_flow_enum)] #![recursion_limit = "256"] diff --git a/compiler/rustc_mir/src/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs index ef79f36b3b5..31cb5484bce 100644 --- a/compiler/rustc_mir/src/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -184,7 +184,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::{par_iter, MTLock, MTRef, ParallelIterator}; use rustc_errors::{ErrorReported, FatalError}; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; +use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::LangItem; use rustc_index::bit_set::GrowableBitSet; @@ -194,6 +194,7 @@ use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; use rustc_middle::mir::visit::Visitor as MirVisitor; use rustc_middle::mir::{self, Local, Location}; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_middle::{middle::codegen_fn_attrs::CodegenFnAttrFlags, mir::visit::TyContext}; @@ -342,7 +343,8 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem< .collect() } -// Collect all monomorphized items reachable from `starting_point` +/// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a +/// post-monorphization error is encountered during a collection step. fn collect_items_rec<'tcx>( tcx: TyCtxt<'tcx>, starting_point: Spanned<MonoItem<'tcx>>, @@ -359,6 +361,31 @@ fn collect_items_rec<'tcx>( let mut neighbors = Vec::new(); let recursion_depth_reset; + // + // Post-monomorphization errors MVP + // + // We can encounter errors while monomorphizing an item, but we don't have a good way of + // showing a complete stack of spans ultimately leading to collecting the erroneous one yet. + // (It's also currently unclear exactly which diagnostics and information would be interesting + // to report in such cases) + // + // This leads to suboptimal error reporting: a post-monomorphization error (PME) will be + // shown with just a spanned piece of code causing the error, without information on where + // it was called from. This is especially obscure if the erroneous mono item is in a + // dependency. See for example issue #85155, where, before minimization, a PME happened two + // crates downstream from libcore's stdarch, without a way to know which dependency was the + // cause. + // + // If such an error occurs in the current crate, its span will be enough to locate the + // source. If the cause is in another crate, the goal here is to quickly locate which mono + // item in the current crate is ultimately responsible for causing the error. + // + // To give at least _some_ context to the user: while collecting mono items, we check the + // error count. If it has changed, a PME occurred, and we trigger some diagnostics about the + // current step of mono items collection. + // + let error_count = tcx.sess.diagnostic().err_count(); + match starting_point.node { MonoItem::Static(def_id) => { let instance = Instance::mono(tcx, def_id); @@ -411,6 +438,20 @@ fn collect_items_rec<'tcx>( } } + // Check for PMEs and emit a diagnostic if one happened. To try to show relevant edges of the + // mono item graph where the PME diagnostics are currently the most problematic (e.g. ones + // involving a dependency, and the lack of context is confusing) in this MVP, we focus on + // diagnostics on edges crossing a crate boundary: the collected mono items which are not + // defined in the local crate. + if tcx.sess.diagnostic().err_count() > error_count && starting_point.node.krate() != LOCAL_CRATE + { + let formatted_item = with_no_trimmed_paths(|| starting_point.node.to_string()); + tcx.sess.span_note_without_error( + starting_point.span, + &format!("the above error was encountered while instantiating `{}`", formatted_item), + ); + } + record_accesses(tcx, starting_point.node, neighbors.iter().map(|i| &i.node), inlining_map); for neighbour in neighbors { diff --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs index 16f5f14f563..dcbc9c523dc 100644 --- a/compiler/rustc_mir/src/transform/check_consts/ops.rs +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -541,30 +541,6 @@ impl NonConstOp for UnionAccess { } } -/// See [#64992]. -/// -/// [#64992]: https://github.com/rust-lang/rust/issues/64992 -#[derive(Debug)] -pub struct UnsizingCast; -impl NonConstOp for UnsizingCast { - fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { - if ccx.const_kind() != hir::ConstContext::ConstFn { - Status::Allowed - } else { - Status::Unstable(sym::const_fn_unsize) - } - } - - fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_fn_unsize, - span, - "unsizing casts to types besides slices are not allowed in const fn", - ) - } -} - // Types that cannot appear in the signature or locals of a `const fn`. pub mod ty { use super::*; diff --git a/compiler/rustc_mir/src/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs index 63fc66f2b9f..ac3420ad339 100644 --- a/compiler/rustc_mir/src/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -10,9 +10,7 @@ use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceC use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{ - self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut, -}; +use rustc_middle::ty::{self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt}; use rustc_middle::ty::{Binder, TraitPredicate, TraitRef}; use rustc_span::{sym, Span, Symbol}; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; @@ -358,10 +356,9 @@ impl Validator<'mir, 'tcx> { } fn check_static(&mut self, def_id: DefId, span: Span) { - assert!( - !self.tcx.is_thread_local_static(def_id), - "tls access is checked in `Rvalue::ThreadLocalRef" - ); + if self.tcx.is_thread_local_static(def_id) { + self.tcx.sess.delay_span_bug(span, "tls access is checked in `Rvalue::ThreadLocalRef"); + } self.check_op_spanned(ops::StaticAccess, span) } @@ -636,17 +633,9 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { _, ) => self.check_op(ops::FnPtrCast), - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, cast_ty) => { - if let Some(TypeAndMut { ty, .. }) = cast_ty.builtin_deref(true) { - let unsized_ty = self.tcx.struct_tail_erasing_lifetimes(ty, self.param_env); - - // Casting/coercing things to slices is fine. - if let ty::Slice(_) | ty::Str = unsized_ty.kind() { - return; - } - } - - self.check_op(ops::UnsizingCast); + Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), _, _) => { + // Nothing to check here (`check_local_or_return_ty` ensures no trait objects occur + // in the type of any local, which also excludes casts). } Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) => { @@ -763,12 +752,8 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { | ProjectionElem::Field(..) | ProjectionElem::Index(_) => { let base_ty = Place::ty_from(place_local, proj_base, self.body, self.tcx).ty; - match base_ty.ty_adt_def() { - Some(def) if def.is_union() => { - self.check_op(ops::UnionAccess); - } - - _ => {} + if base_ty.is_union() { + self.check_op(ops::UnionAccess); } } } diff --git a/compiler/rustc_mir/src/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs index 955be8cc81e..103ddda1a1d 100644 --- a/compiler/rustc_mir/src/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } let base_ty = base.ty(self.body, self.tcx).ty; - if base_ty.ty_adt_def().map_or(false, |adt| adt.is_union()) { + if base_ty.is_union() { // If we did not hit a `Deref` yet and the overall place use is an assignment, the // rules are different. let assign_to_field = !saw_deref @@ -376,6 +376,12 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { /// Checks whether calling `func_did` needs an `unsafe` context or not, i.e. whether /// the called function has target features the calling function hasn't. fn check_target_features(&mut self, func_did: DefId) { + // Unsafety isn't required on wasm targets. For more information see + // the corresponding check in typeck/src/collect.rs + if self.tcx.sess.target.options.is_like_wasm { + return; + } + let callee_features = &self.tcx.codegen_fn_attrs(func_did).target_features; let self_features = &self.tcx.codegen_fn_attrs(self.body_did).target_features; diff --git a/compiler/rustc_mir/src/transform/const_goto.rs b/compiler/rustc_mir/src/transform/const_goto.rs index b5c8b4bebc3..ba10b54c5ae 100644 --- a/compiler/rustc_mir/src/transform/const_goto.rs +++ b/compiler/rustc_mir/src/transform/const_goto.rs @@ -47,7 +47,7 @@ impl<'tcx> MirPass<'tcx> for ConstGoto { // if we applied optimizations, we potentially have some cfg to cleanup to // make it easier for further passes if should_simplify { - simplify_cfg(body); + simplify_cfg(tcx, body); simplify_locals(body, tcx); } } diff --git a/compiler/rustc_mir/src/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs index 5968bbbfca7..681d63c6fc9 100644 --- a/compiler/rustc_mir/src/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -33,6 +33,7 @@ use crate::interpret::{ self, compile_time_machine, AllocId, Allocation, ConstValue, CtfeValidationMode, Frame, ImmTy, Immediate, InterpCx, InterpResult, LocalState, LocalValue, MemPlace, Memory, MemoryKind, OpTy, Operand as InterpOperand, PlaceTy, Pointer, Scalar, ScalarMaybeUninit, StackPopCleanup, + StackPopUnwind, }; use crate::transform::MirPass; @@ -198,7 +199,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _abi: Abi, _args: &[OpTy<'tcx>], _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>, - _unwind: Option<BasicBlock>, + _unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<&'mir Body<'tcx>>> { Ok(None) } @@ -208,7 +209,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for ConstPropMachine<'mir, 'tcx> _instance: ty::Instance<'tcx>, _args: &[OpTy<'tcx>], _ret: Option<(&PlaceTy<'tcx>, BasicBlock)>, - _unwind: Option<BasicBlock>, + _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { throw_machine_stop_str!("calling intrinsics isn't supported in ConstProp") } diff --git a/compiler/rustc_mir/src/transform/coverage/debug.rs b/compiler/rustc_mir/src/transform/coverage/debug.rs index 2397d627880..f6672335cb1 100644 --- a/compiler/rustc_mir/src/transform/coverage/debug.rs +++ b/compiler/rustc_mir/src/transform/coverage/debug.rs @@ -116,7 +116,6 @@ use crate::util::pretty; use crate::util::spanview::{self, SpanViewable}; use rustc_data_structures::fx::FxHashMap; -use rustc_index::vec::Idx; use rustc_middle::mir::coverage::*; use rustc_middle::mir::{self, BasicBlock, TerminatorKind}; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs index c41e71e09a4..912505c6598 100644 --- a/compiler/rustc_mir/src/transform/deduplicate_blocks.rs +++ b/compiler/rustc_mir/src/transform/deduplicate_blocks.rs @@ -26,7 +26,7 @@ impl<'tcx> MirPass<'tcx> for DeduplicateBlocks { if has_opts_to_apply { let mut opt_applier = OptApplier { tcx, duplicates }; opt_applier.visit_body(body); - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs index 29df86ca6cd..4f5a467a6ee 100644 --- a/compiler/rustc_mir/src/transform/dest_prop.rs +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -114,7 +114,7 @@ use rustc_middle::mir::{ traversal, Body, InlineAsmOperand, Local, LocalKind, Location, Operand, Place, PlaceElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::TyCtxt; // Empirical measurements have resulted in some observations: // - Running on a body with a single block and 500 locals takes barely any time @@ -910,17 +910,8 @@ impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { // Handle the "subtle case" described above by rejecting any `dest` that is or // projects through a union. - let is_union = |ty: Ty<'_>| { - if let ty::Adt(def, _) = ty.kind() { - if def.is_union() { - return true; - } - } - - false - }; let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty); - if is_union(place_ty.ty) { + if place_ty.ty.is_union() { return; } for elem in dest.projection { @@ -930,7 +921,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindAssignments<'a, 'tcx> { } place_ty = place_ty.projection_ty(self.tcx, elem); - if is_union(place_ty.ty) { + if place_ty.ty.is_union() { return; } } diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs index 7934d4ba849..07127042fa4 100644 --- a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -164,7 +164,7 @@ impl<'tcx> MirPass<'tcx> for EarlyOtherwiseBranch { // Since this optimization adds new basic blocks and invalidates others, // clean up the cfg to make it nicer for other passes if should_cleanup { - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs index 003003a8abb..3560b4b1e86 100644 --- a/compiler/rustc_mir/src/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -964,7 +964,7 @@ fn create_generator_drop_shim<'tcx>( // Make sure we remove dead blocks to remove // unrelated code from the resume part of the function - simplify::remove_dead_blocks(&mut body); + simplify::remove_dead_blocks(tcx, &mut body); dump_mir(tcx, None, "generator_drop", &0, &body, |_, _| Ok(())); @@ -1137,7 +1137,7 @@ fn create_generator_resume_function<'tcx>( // Make sure we remove dead blocks to remove // unrelated code from the drop part of the function - simplify::remove_dead_blocks(body); + simplify::remove_dead_blocks(tcx, body); dump_mir(tcx, None, "generator_resume", &0, body, |_, _| Ok(())); } diff --git a/compiler/rustc_mir/src/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs index b6f80763bc8..f1c95a84ade 100644 --- a/compiler/rustc_mir/src/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -57,7 +57,7 @@ impl<'tcx> MirPass<'tcx> for Inline { if inline(tcx, body) { debug!("running simplify cfg on {:?}", body.source); CfgSimplifier::new(body).simplify(); - remove_dead_blocks(body); + remove_dead_blocks(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs index f7a9835353e..21b208a08c2 100644 --- a/compiler/rustc_mir/src/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -167,7 +167,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { } if should_cleanup { - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs index 4aaa0baa9f4..cd2db180552 100644 --- a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs +++ b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs @@ -38,6 +38,6 @@ impl<'tcx> MirPass<'tcx> for MultipleReturnTerminators { } } - simplify::remove_dead_blocks(body) + simplify::remove_dead_blocks(tcx, body) } } diff --git a/compiler/rustc_mir/src/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs index f6b1323e107..78e84419c62 100644 --- a/compiler/rustc_mir/src/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -415,11 +415,9 @@ impl<'tcx> Validator<'_, 'tcx> { ProjectionElem::Field(..) => { let base_ty = place_base.ty(self.body, self.tcx).ty; - if let Some(def) = base_ty.ty_adt_def() { + if base_ty.is_union() { // No promotion of union field accesses. - if def.is_union() { - return Err(Unpromotable); - } + return Err(Unpromotable); } } } diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs index 5144d48750d..02e45021a0a 100644 --- a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -36,7 +36,7 @@ impl<'tcx> MirPass<'tcx> for RemoveUnneededDrops { // if we applied optimizations, we potentially have some cfg to cleanup to // make it easier for further passes if should_simplify { - simplify_cfg(body); + simplify_cfg(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/remove_zsts.rs b/compiler/rustc_mir/src/transform/remove_zsts.rs index 70f7538dd57..a0f225e6de6 100644 --- a/compiler/rustc_mir/src/transform/remove_zsts.rs +++ b/compiler/rustc_mir/src/transform/remove_zsts.rs @@ -69,21 +69,14 @@ fn involves_a_union<'tcx>( tcx: TyCtxt<'tcx>, ) -> bool { let mut place_ty = PlaceTy::from_ty(local_decls[place.local].ty); - if is_union(place_ty.ty) { + if place_ty.ty.is_union() { return true; } for elem in place.projection { place_ty = place_ty.projection_ty(tcx, elem); - if is_union(place_ty.ty) { + if place_ty.ty.is_union() { return true; } } return false; } - -fn is_union(ty: Ty<'_>) -> bool { - match ty.kind() { - ty::Adt(def, _) if def.is_union() => true, - _ => false, - } -} diff --git a/compiler/rustc_mir/src/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs index 65e2d096b20..7aebca77e6f 100644 --- a/compiler/rustc_mir/src/transform/simplify.rs +++ b/compiler/rustc_mir/src/transform/simplify.rs @@ -29,6 +29,7 @@ use crate::transform::MirPass; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::coverage::*; use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; @@ -46,9 +47,9 @@ impl SimplifyCfg { } } -pub fn simplify_cfg(body: &mut Body<'_>) { +pub fn simplify_cfg(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) { CfgSimplifier::new(body).simplify(); - remove_dead_blocks(body); + remove_dead_blocks(tcx, body); // FIXME: Should probably be moved into some kind of pass manager body.basic_blocks_mut().raw.shrink_to_fit(); @@ -59,9 +60,9 @@ impl<'tcx> MirPass<'tcx> for SimplifyCfg { Cow::Borrowed(&self.label) } - fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source); - simplify_cfg(body); + simplify_cfg(tcx, body); } } @@ -286,7 +287,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { } } -pub fn remove_dead_blocks(body: &mut Body<'_>) { +pub fn remove_dead_blocks(tcx: TyCtxt<'tcx>, body: &mut Body<'_>) { let reachable = traversal::reachable_as_bitset(body); let num_blocks = body.basic_blocks().len(); if num_blocks == reachable.count() { @@ -306,6 +307,11 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { } used_blocks += 1; } + + if tcx.sess.instrument_coverage() { + save_unreachable_coverage(basic_blocks, used_blocks); + } + basic_blocks.raw.truncate(used_blocks); for block in basic_blocks { @@ -315,6 +321,75 @@ pub fn remove_dead_blocks(body: &mut Body<'_>) { } } +/// Some MIR transforms can determine at compile time that a sequences of +/// statements will never be executed, so they can be dropped from the MIR. +/// For example, an `if` or `else` block that is guaranteed to never be executed +/// because its condition can be evaluated at compile time, such as by const +/// evaluation: `if false { ... }`. +/// +/// Those statements are bypassed by redirecting paths in the CFG around the +/// `dead blocks`; but with `-Z instrument-coverage`, the dead blocks usually +/// include `Coverage` statements representing the Rust source code regions to +/// be counted at runtime. Without these `Coverage` statements, the regions are +/// lost, and the Rust source code will show no coverage information. +/// +/// What we want to show in a coverage report is the dead code with coverage +/// counts of `0`. To do this, we need to save the code regions, by injecting +/// `Unreachable` coverage statements. These are non-executable statements whose +/// code regions are still recorded in the coverage map, representing regions +/// with `0` executions. +fn save_unreachable_coverage( + basic_blocks: &mut IndexVec<BasicBlock, BasicBlockData<'_>>, + first_dead_block: usize, +) { + let has_live_counters = basic_blocks.raw[0..first_dead_block].iter().any(|live_block| { + live_block.statements.iter().any(|statement| { + if let StatementKind::Coverage(coverage) = &statement.kind { + matches!(coverage.kind, CoverageKind::Counter { .. }) + } else { + false + } + }) + }); + if !has_live_counters { + // If there are no live `Counter` `Coverage` statements anymore, don't + // move dead coverage to the `START_BLOCK`. Just allow the dead + // `Coverage` statements to be dropped with the dead blocks. + // + // The `generator::StateTransform` MIR pass can create atypical + // conditions, where all live `Counter`s are dropped from the MIR. + // + // At least one Counter per function is required by LLVM (and necessary, + // to add the `function_hash` to the counter's call to the LLVM + // intrinsic `instrprof.increment()`). + return; + } + + // Retain coverage info for dead blocks, so coverage reports will still + // report `0` executions for the uncovered code regions. + let mut dropped_coverage = Vec::new(); + for dead_block in basic_blocks.raw[first_dead_block..].iter() { + for statement in dead_block.statements.iter() { + if let StatementKind::Coverage(coverage) = &statement.kind { + if let Some(code_region) = &coverage.code_region { + dropped_coverage.push((statement.source_info, code_region.clone())); + } + } + } + } + + let start_block = &mut basic_blocks[START_BLOCK]; + for (source_info, code_region) in dropped_coverage { + start_block.statements.push(Statement { + source_info, + kind: StatementKind::Coverage(box Coverage { + kind: CoverageKind::Unreachable, + code_region: Some(code_region), + }), + }) + } +} + pub struct SimplifyLocals; impl<'tcx> MirPass<'tcx> for SimplifyLocals { diff --git a/compiler/rustc_mir/src/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs index 89fddc95c98..dd2ec39c066 100644 --- a/compiler/rustc_mir/src/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -558,7 +558,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyBranchSame { if did_remove_blocks { // We have dead blocks now, so remove those. - simplify::remove_dead_blocks(body); + simplify::remove_dead_blocks(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs index 658c6b6e9db..e7fb6b4f6b4 100644 --- a/compiler/rustc_mir/src/transform/unreachable_prop.rs +++ b/compiler/rustc_mir/src/transform/unreachable_prop.rs @@ -60,7 +60,7 @@ impl MirPass<'_> for UnreachablePropagation { } if replaced { - simplify::remove_dead_blocks(body); + simplify::remove_dead_blocks(tcx, body); } } } diff --git a/compiler/rustc_mir/src/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs index d009b0b1b23..835789069bb 100644 --- a/compiler/rustc_mir/src/transform/validate.rs +++ b/compiler/rustc_mir/src/transform/validate.rs @@ -11,8 +11,9 @@ use rustc_middle::mir::interpret::Scalar; use rustc_middle::mir::traversal; use rustc_middle::mir::visit::{PlaceContext, Visitor}; use rustc_middle::mir::{ - AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceRef, - Rvalue, SourceScope, Statement, StatementKind, Terminator, TerminatorKind, + AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, PlaceElem, + PlaceRef, ProjectionElem, Rvalue, SourceScope, Statement, StatementKind, Terminator, + TerminatorKind, }; use rustc_middle::ty::fold::BottomUpFolder; use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable}; @@ -217,6 +218,23 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { self.super_operand(operand, location); } + fn visit_projection_elem( + &mut self, + local: Local, + proj_base: &[PlaceElem<'tcx>], + elem: PlaceElem<'tcx>, + context: PlaceContext, + location: Location, + ) { + if let ProjectionElem::Index(index) = elem { + let index_ty = self.body.local_decls[index].ty; + if index_ty != self.tcx.types.usize { + self.fail(location, format!("bad index ({:?} != usize)", index_ty)) + } + } + self.super_projection_elem(local, proj_base, elem, context, location); + } + fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) { match &statement.kind { StatementKind::Assign(box (dest, rvalue)) => { diff --git a/compiler/rustc_mir/src/util/generic_graph.rs b/compiler/rustc_mir/src/util/generic_graph.rs index 6ce305a4821..770b52a4d4b 100644 --- a/compiler/rustc_mir/src/util/generic_graph.rs +++ b/compiler/rustc_mir/src/util/generic_graph.rs @@ -1,6 +1,5 @@ use gsgdt::{Edge, Graph, Node, NodeStyle}; use rustc_hir::def_id::DefId; -use rustc_index::vec::Idx; use rustc_middle::mir::*; use rustc_middle::ty::TyCtxt; diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs index 808c6e3ff64..8426b24270d 100644 --- a/compiler/rustc_mir_build/src/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -1,8 +1,8 @@ use crate::build::matches::ArmHasGuard; use crate::build::ForGuard::OutsideGuard; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; -use crate::thir::*; use rustc_middle::mir::*; +use rustc_middle::thir::*; use rustc_session::lint::builtin::UNSAFE_OP_IN_UNSAFE_FN; use rustc_session::lint::Level; use rustc_span::Span; @@ -12,18 +12,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, destination: Place<'tcx>, block: BasicBlock, - ast_block: &Block<'_, 'tcx>, + ast_block: &Block, source_info: SourceInfo, ) -> BlockAnd<()> { let Block { region_scope, opt_destruction_scope, span, - stmts, + ref stmts, expr, targeted_by_break, safety_mode, } = *ast_block; + let expr = expr.map(|expr| &self.thir[expr]); self.in_opt_scope(opt_destruction_scope.map(|de| (de, source_info)), move |this| { this.in_scope((region_scope, source_info), LintLevel::Inherited, move |this| { if targeted_by_break { @@ -32,13 +33,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination, block, span, - stmts, + &stmts, expr, safety_mode, )) }) } else { - this.ast_block_stmts(destination, block, span, stmts, expr, safety_mode) + this.ast_block_stmts(destination, block, span, &stmts, expr, safety_mode) } }) }) @@ -49,8 +50,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: Place<'tcx>, mut block: BasicBlock, span: Span, - stmts: &[Stmt<'_, 'tcx>], - expr: Option<&Expr<'_, 'tcx>>, + stmts: &[StmtId], + expr: Option<&Expr<'tcx>>, safety_mode: BlockSafety, ) -> BlockAnd<()> { let this = self; @@ -78,23 +79,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.update_source_scope_for_safety_mode(span, safety_mode); let source_info = this.source_info(span); - for Stmt { kind, opt_destruction_scope } in stmts { + for stmt in stmts { + let Stmt { ref kind, opt_destruction_scope } = this.thir[*stmt]; match kind { - &StmtKind::Expr { scope, expr } => { + StmtKind::Expr { scope, expr } => { this.block_context.push(BlockFrame::Statement { ignores_expr_result: true }); unpack!( block = this.in_opt_scope( opt_destruction_scope.map(|de| (de, source_info)), |this| { - let si = (scope, source_info); + let si = (*scope, source_info); this.in_scope(si, LintLevel::Inherited, |this| { - this.stmt_expr(block, expr, Some(scope)) + this.stmt_expr(block, &this.thir[*expr], Some(*scope)) }) } ) ); } - StmtKind::Let { remainder_scope, init_scope, pattern, initializer, lint_level } => { + StmtKind::Let { + remainder_scope, + init_scope, + ref pattern, + initializer, + lint_level, + } => { let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild); this.block_context.push(BlockFrame::Statement { ignores_expr_result }); @@ -110,6 +118,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // Evaluate the initializer, if present. if let Some(init) = initializer { + let init = &this.thir[*init]; let initializer_span = init.span; unpack!( @@ -145,7 +154,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { debug!("ast_block_stmts: pattern={:?}", pattern); this.visit_primary_bindings( - &pattern, + pattern, UserTypeProjections::none(), &mut |this, _, _, _, node, span, _, _| { this.storage_live_binding(block, node, span, OutsideGuard, true); diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs index 57f56e2d092..5e305ebba2f 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -1,18 +1,20 @@ //! See docs in build/expr/mod.rs use crate::build::Builder; -use crate::thir::*; use rustc_middle::mir::*; +use rustc_middle::thir::*; use rustc_middle::ty::CanonicalUserTypeAnnotation; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, yielding a compile-time constant. Assumes that /// `expr` is a valid compile-time constant! - crate fn as_constant(&mut self, expr: &Expr<'_, 'tcx>) -> Constant<'tcx> { + crate fn as_constant(&mut self, expr: &Expr<'tcx>) -> Constant<'tcx> { let this = self; let Expr { ty, temp_lifetime: _, span, ref kind } = *expr; match *kind { - ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value), + ExprKind::Scope { region_scope: _, lint_level: _, value } => { + this.as_constant(&this.thir[value]) + } ExprKind::Literal { literal, user_ty, const_id: _ } => { let user_ty = user_ty.map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs index c393878e0b9..b2a1dbf4c52 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs @@ -2,9 +2,9 @@ use crate::build::expr::category::Category; use crate::build::{BlockAnd, BlockAndExtension, Builder}; -use crate::thir::*; use rustc_middle::middle::region; use rustc_middle::mir::*; +use rustc_middle::thir::*; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Returns an operand suitable for use until the end of the current @@ -17,7 +17,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn as_local_operand( &mut self, block: BasicBlock, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, ) -> BlockAnd<Operand<'tcx>> { let local_scope = self.local_scope(); self.as_operand(block, Some(local_scope), expr) @@ -74,7 +74,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn as_local_call_operand( &mut self, block: BasicBlock, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, ) -> BlockAnd<Operand<'tcx>> { let local_scope = self.local_scope(); self.as_call_operand(block, Some(local_scope), expr) @@ -93,7 +93,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, scope: Option<region::Scope>, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, ) -> BlockAnd<Operand<'tcx>> { debug!("as_operand(block={:?}, expr={:?})", block, expr); let this = self; @@ -101,8 +101,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); - return this - .in_scope(region_scope, lint_level, |this| this.as_operand(block, scope, value)); + return this.in_scope(region_scope, lint_level, |this| { + this.as_operand(block, scope, &this.thir[value]) + }); } let category = Category::of(&expr.kind).unwrap(); @@ -123,7 +124,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, scope: Option<region::Scope>, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, ) -> BlockAnd<Operand<'tcx>> { debug!("as_call_operand(block={:?}, expr={:?})", block, expr); let this = self; @@ -132,7 +133,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = this.source_info(expr.span); let region_scope = (region_scope, source_info); return this.in_scope(region_scope, lint_level, |this| { - this.as_call_operand(block, scope, value) + this.as_call_operand(block, scope, &this.thir[value]) }); } @@ -151,7 +152,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // type, and that value is coming from the deref of a box. if let ExprKind::Deref { arg } = expr.kind { // Generate let tmp0 = arg0 - let operand = unpack!(block = this.as_temp(block, scope, arg, Mutability::Mut)); + let operand = unpack!( + block = this.as_temp(block, scope, &this.thir[arg], Mutability::Mut) + ); // Return the operand *tmp0 to be used as the call argument let place = Place { diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 1053890e618..5511cd4c73b 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -3,13 +3,13 @@ use crate::build::expr::category::Category; use crate::build::ForGuard::{OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; -use crate::thir::*; use rustc_hir::def_id::DefId; use rustc_hir::HirId; use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::middle::region; use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; +use rustc_middle::thir::*; use rustc_middle::ty::AdtDef; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance}; use rustc_span::Span; @@ -209,9 +209,7 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( match from_builder.base { PlaceBase::Local(_) => Ok(from_builder), PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => { - // Captures are represented using fields inside a structure. - // This represents accessing self in the closure structure - let mut upvar_resolved_place_builder = PlaceBuilder::from(Local::new(1)); + let mut upvar_resolved_place_builder = PlaceBuilder::from(ty::CAPTURE_STRUCT_LOCAL); match closure_kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => { upvar_resolved_place_builder = upvar_resolved_place_builder.deref(); @@ -381,7 +379,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn as_place( &mut self, mut block: BasicBlock, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, ) -> BlockAnd<Place<'tcx>> { let place_builder = unpack!(block = self.as_place_builder(block, expr)); block.and(place_builder.into_place(self.tcx, self.typeck_results)) @@ -392,7 +390,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn as_place_builder( &mut self, block: BasicBlock, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, ) -> BlockAnd<PlaceBuilder<'tcx>> { self.expr_as_place(block, expr, Mutability::Mut, None) } @@ -405,7 +403,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn as_read_only_place( &mut self, mut block: BasicBlock, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, ) -> BlockAnd<Place<'tcx>> { let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr)); block.and(place_builder.into_place(self.tcx, self.typeck_results)) @@ -420,7 +418,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn as_read_only_place_builder( &mut self, block: BasicBlock, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, ) -> BlockAnd<PlaceBuilder<'tcx>> { self.expr_as_place(block, expr, Mutability::Not, None) } @@ -428,7 +426,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn expr_as_place( &mut self, mut block: BasicBlock, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, mutability: Mutability, fake_borrow_temps: Option<&mut Vec<Local>>, ) -> BlockAnd<PlaceBuilder<'tcx>> { @@ -440,23 +438,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match expr.kind { ExprKind::Scope { region_scope, lint_level, value } => { this.in_scope((region_scope, source_info), lint_level, |this| { - this.expr_as_place(block, value, mutability, fake_borrow_temps) + this.expr_as_place(block, &this.thir[value], mutability, fake_borrow_temps) }) } ExprKind::Field { lhs, name } => { - let place_builder = - unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,)); + let place_builder = unpack!( + block = + this.expr_as_place(block, &this.thir[lhs], mutability, fake_borrow_temps,) + ); block.and(place_builder.field(name, expr.ty)) } ExprKind::Deref { arg } => { - let place_builder = - unpack!(block = this.expr_as_place(block, arg, mutability, fake_borrow_temps,)); + let place_builder = unpack!( + block = + this.expr_as_place(block, &this.thir[arg], mutability, fake_borrow_temps,) + ); block.and(place_builder.deref()) } ExprKind::Index { lhs, index } => this.lower_index_expression( block, - lhs, - index, + &this.thir[lhs], + &this.thir[index], mutability, fake_borrow_temps, expr.temp_lifetime, @@ -481,7 +483,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::PlaceTypeAscription { source, user_ty } => { let place_builder = unpack!( - block = this.expr_as_place(block, source, mutability, fake_borrow_temps,) + block = this.expr_as_place( + block, + &this.thir[source], + mutability, + fake_borrow_temps, + ) ); if let Some(user_ty) = user_ty { let annotation_index = @@ -509,6 +516,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(place_builder) } ExprKind::ValueTypeAscription { source, user_ty } => { + let source = &this.thir[source]; let temp = unpack!(block = this.as_temp(block, source.temp_lifetime, source, mutability)); if let Some(user_ty) = user_ty { @@ -613,8 +621,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn lower_index_expression( &mut self, mut block: BasicBlock, - base: &Expr<'_, 'tcx>, - index: &Expr<'_, 'tcx>, + base: &Expr<'tcx>, + index: &Expr<'tcx>, mutability: Mutability, fake_borrow_temps: Option<&mut Vec<Local>>, temp_lifetime: Option<region::Scope>, diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 822fbd91c94..69786c14ee8 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -5,11 +5,11 @@ use rustc_index::vec::Idx; use crate::build::expr::as_place::PlaceBase; use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; -use crate::thir::*; use rustc_middle::middle::region; use rustc_middle::mir::AssertKind; use rustc_middle::mir::Place; use rustc_middle::mir::*; +use rustc_middle::thir::*; use rustc_middle::ty::{self, Ty, UpvarSubsts}; use rustc_span::Span; @@ -23,7 +23,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn as_local_rvalue( &mut self, block: BasicBlock, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, ) -> BlockAnd<Rvalue<'tcx>> { let local_scope = self.local_scope(); self.as_rvalue(block, Some(local_scope), expr) @@ -34,7 +34,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, scope: Option<region::Scope>, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, ) -> BlockAnd<Rvalue<'tcx>> { debug!("expr_as_rvalue(block={:?}, scope={:?}, expr={:?})", block, scope, expr); @@ -46,19 +46,22 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::ThreadLocalRef(did) => block.and(Rvalue::ThreadLocalRef(did)), ExprKind::Scope { region_scope, lint_level, value } => { let region_scope = (region_scope, source_info); - this.in_scope(region_scope, lint_level, |this| this.as_rvalue(block, scope, value)) + this.in_scope(region_scope, lint_level, |this| { + this.as_rvalue(block, scope, &this.thir[value]) + }) } ExprKind::Repeat { value, count } => { - let value_operand = unpack!(block = this.as_operand(block, scope, value)); + let value_operand = + unpack!(block = this.as_operand(block, scope, &this.thir[value])); block.and(Rvalue::Repeat(value_operand, count)) } ExprKind::Binary { op, lhs, rhs } => { - let lhs = unpack!(block = this.as_operand(block, scope, lhs)); - let rhs = unpack!(block = this.as_operand(block, scope, rhs)); + let lhs = unpack!(block = this.as_operand(block, scope, &this.thir[lhs])); + let rhs = unpack!(block = this.as_operand(block, scope, &this.thir[rhs])); this.build_binary_op(block, op, expr_span, expr.ty, lhs, rhs) } ExprKind::Unary { op, arg } => { - let arg = unpack!(block = this.as_operand(block, scope, arg)); + let arg = unpack!(block = this.as_operand(block, scope, &this.thir[arg])); // Check for -MIN on signed integers if this.check_overflow && op == UnOp::Neg && expr.ty.is_signed() { let bool_ty = this.tcx.types.bool; @@ -84,6 +87,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::UnaryOp(op, arg)) } ExprKind::Box { value } => { + let value = &this.thir[value]; // The `Box<T>` temporary created here is not a part of the HIR, // and therefore is not considered during generator auto-trait // determination. See the comment about `box` at `yield_in_scope`. @@ -112,14 +116,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.and(Rvalue::Use(Operand::Move(Place::from(result)))) } ExprKind::Cast { source } => { - let source = unpack!(block = this.as_operand(block, scope, source)); + let source = unpack!(block = this.as_operand(block, scope, &this.thir[source])); block.and(Rvalue::Cast(CastKind::Misc, source, expr.ty)) } ExprKind::Pointer { cast, source } => { - let source = unpack!(block = this.as_operand(block, scope, source)); + let source = unpack!(block = this.as_operand(block, scope, &this.thir[source])); block.and(Rvalue::Cast(CastKind::Pointer(cast), source, expr.ty)) } - ExprKind::Array { fields } => { + ExprKind::Array { ref fields } => { // (*) We would (maybe) be closer to codegen if we // handled this and other aggregate cases via // `into()`, not `as_rvalue` -- in that case, instead @@ -150,22 +154,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let el_ty = expr.ty.sequence_element_type(this.tcx); let fields: Vec<_> = fields .into_iter() - .map(|f| unpack!(block = this.as_operand(block, scope, f))) + .copied() + .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f]))) .collect(); block.and(Rvalue::Aggregate(box AggregateKind::Array(el_ty), fields)) } - ExprKind::Tuple { fields } => { + ExprKind::Tuple { ref fields } => { // see (*) above // first process the set of fields let fields: Vec<_> = fields .into_iter() - .map(|f| unpack!(block = this.as_operand(block, scope, f))) + .copied() + .map(|f| unpack!(block = this.as_operand(block, scope, &this.thir[f]))) .collect(); block.and(Rvalue::Aggregate(box AggregateKind::Tuple, fields)) } - ExprKind::Closure { closure_id, substs, upvars, movability, ref fake_reads } => { + ExprKind::Closure { closure_id, substs, ref upvars, movability, ref fake_reads } => { // Convert the closure fake reads, if any, from `ExprRef` to mir `Place` // and push the fake reads. // This must come before creating the operands. This is required in case @@ -179,8 +185,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // match x { _ => () } // fake read of `x` // }; // ``` + // for (thir_place, cause, hir_id) in fake_reads.into_iter() { - let place_builder = unpack!(block = this.as_place_builder(block, thir_place)); + let place_builder = + unpack!(block = this.as_place_builder(block, &this.thir[*thir_place])); if let Ok(place_builder_resolved) = place_builder.try_upvars_resolved(this.tcx, this.typeck_results) @@ -199,7 +207,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // see (*) above let operands: Vec<_> = upvars .into_iter() + .copied() .map(|upvar| { + let upvar = &this.thir[upvar]; match Category::of(&upvar.kind) { // Use as_place to avoid creating a temporary when // moving a variable into a closure, so that @@ -225,7 +235,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { arg, } => unpack!( block = this.limit_capture_mutability( - upvar.span, upvar.ty, scope, block, arg, + upvar.span, + upvar.ty, + scope, + block, + &this.thir[arg], ) ), _ => unpack!(block = this.as_operand(block, scope, upvar)), @@ -398,7 +412,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { upvar_ty: Ty<'tcx>, temp_lifetime: Option<region::Scope>, mut block: BasicBlock, - arg: &Expr<'_, 'tcx>, + arg: &Expr<'tcx>, ) -> BlockAnd<Operand<'tcx>> { let this = self; @@ -433,7 +447,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } => { // Not in a closure debug_assert!( - local == Local::new(1), + local == ty::CAPTURE_STRUCT_LOCAL, "Expected local to be Local(1), found {:?}", local ); diff --git a/compiler/rustc_mir_build/src/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs index 98b910ab21c..45e0243c88a 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -2,10 +2,10 @@ use crate::build::scope::DropKind; use crate::build::{BlockAnd, BlockAndExtension, Builder}; -use crate::thir::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_middle::middle::region; use rustc_middle::mir::*; +use rustc_middle::thir::*; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr` into a fresh temporary. This is used when building @@ -14,7 +14,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, block: BasicBlock, temp_lifetime: Option<region::Scope>, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, mutability: Mutability, ) -> BlockAnd<Local> { // this is the only place in mir building that we need to truly need to worry about @@ -27,7 +27,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, temp_lifetime: Option<region::Scope>, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, mutability: Mutability, ) -> BlockAnd<Local> { debug!( @@ -40,7 +40,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let source_info = this.source_info(expr_span); if let ExprKind::Scope { region_scope, lint_level, value } = expr.kind { return this.in_scope((region_scope, source_info), lint_level, |this| { - this.as_temp(block, temp_lifetime, value, mutability) + this.as_temp(block, temp_lifetime, &this.thir[value], mutability) }); } diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs index 0cadfa2f0a1..c834ce6ce68 100644 --- a/compiler/rustc_mir_build/src/build/expr/category.rs +++ b/compiler/rustc_mir_build/src/build/expr/category.rs @@ -1,4 +1,4 @@ -use crate::thir::*; +use rustc_middle::thir::*; #[derive(Debug, PartialEq)] crate enum Category { @@ -31,7 +31,7 @@ crate enum RvalueFunc { /// Determines the category for a given expression. Note that scope /// and paren expressions have no category. impl Category { - crate fn of(ek: &ExprKind<'_, '_>) -> Option<Category> { + crate fn of(ek: &ExprKind<'_>) -> Option<Category> { match *ek { ExprKind::Scope { .. } => None, diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 1e7ed3d95d2..f2b00f0f6ed 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -2,13 +2,13 @@ use crate::build::expr::category::{Category, RvalueFunc}; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; -use crate::thir::*; use rustc_ast::InlineAsmOptions; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_index::vec::Idx; use rustc_middle::mir::*; +use rustc_middle::thir::*; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation}; use std::iter; @@ -19,7 +19,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, destination: Place<'tcx>, mut block: BasicBlock, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, ) -> BlockAnd<()> { debug!("expr_into_dest(destination={:?}, block={:?}, expr={:?})", destination, block, expr); @@ -42,19 +42,24 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let region_scope = (region_scope, source_info); ensure_sufficient_stack(|| { this.in_scope(region_scope, lint_level, |this| { - this.expr_into_dest(destination, block, value) + this.expr_into_dest(destination, block, &this.thir[value]) }) }) } ExprKind::Block { body: ref ast_block } => { this.ast_block(destination, block, ast_block, source_info) } - ExprKind::Match { scrutinee, arms } => { - this.match_expr(destination, expr_span, block, scrutinee, arms) + ExprKind::Match { scrutinee, ref arms } => { + this.match_expr(destination, expr_span, block, &this.thir[scrutinee], arms) } ExprKind::If { cond, then, else_opt } => { let place = unpack!( - block = this.as_temp(block, Some(this.local_scope()), cond, Mutability::Mut) + block = this.as_temp( + block, + Some(this.local_scope()), + &this.thir[cond], + Mutability::Mut + ) ); let operand = Operand::Move(Place::from(place)); @@ -63,9 +68,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let term = TerminatorKind::if_(this.tcx, operand, then_block, else_block); this.cfg.terminate(block, source_info, term); - unpack!(then_block = this.expr_into_dest(destination, then_block, then)); + unpack!( + then_block = this.expr_into_dest(destination, then_block, &this.thir[then]) + ); else_block = if let Some(else_opt) = else_opt { - unpack!(this.expr_into_dest(destination, else_block, else_opt)) + unpack!(this.expr_into_dest(destination, else_block, &this.thir[else_opt])) } else { // Body of the `if` expression without an `else` clause must return `()`, thus // we implicitly generate a `else {}` if it is not specified. @@ -89,6 +96,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { join_block.unit() } ExprKind::NeverToAny { source } => { + let source = &this.thir[source]; let is_call = matches!(source.kind, ExprKind::Call { .. } | ExprKind::InlineAsm { .. }); @@ -127,7 +135,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.start_new_block(), ); - let lhs = unpack!(block = this.as_local_operand(block, lhs)); + let lhs = unpack!(block = this.as_local_operand(block, &this.thir[lhs])); let blocks = match op { LogicalOp::And => (else_block, shortcircuit_block), LogicalOp::Or => (shortcircuit_block, else_block), @@ -150,7 +158,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); this.cfg.goto(shortcircuit_block, source_info, join_block); - let rhs = unpack!(else_block = this.as_local_operand(else_block, rhs)); + let rhs = unpack!(else_block = this.as_local_operand(else_block, &this.thir[rhs])); this.cfg.push_assign(else_block, source_info, destination, Rvalue::Use(rhs)); this.cfg.goto(else_block, source_info, join_block); @@ -186,18 +194,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // introduce a unit temporary as the destination for the loop body. let tmp = this.get_unit_temp(); // Execute the body, branching back to the test. - let body_block_end = unpack!(this.expr_into_dest(tmp, body_block, body)); + let body_block_end = + unpack!(this.expr_into_dest(tmp, body_block, &this.thir[body])); this.cfg.goto(body_block_end, source_info, loop_block); // Loops are only exited by `break` expressions. None }) } - ExprKind::Call { ty: _, fun, args, from_hir_call, fn_span } => { - let fun = unpack!(block = this.as_local_operand(block, fun)); + ExprKind::Call { ty: _, fun, ref args, from_hir_call, fn_span } => { + let fun = unpack!(block = this.as_local_operand(block, &this.thir[fun])); let args: Vec<_> = args .into_iter() - .map(|arg| unpack!(block = this.as_local_call_operand(block, arg))) + .copied() + .map(|arg| unpack!(block = this.as_local_call_operand(block, &this.thir[arg]))) .collect(); let success = this.cfg.start_new_block(); @@ -228,8 +238,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.diverge_from(block); success.unit() } - ExprKind::Use { source } => this.expr_into_dest(destination, block, source), + ExprKind::Use { source } => this.expr_into_dest(destination, block, &this.thir[source]), ExprKind::Borrow { arg, borrow_kind } => { + let arg = &this.thir[arg]; // We don't do this in `as_rvalue` because we use `as_place` // for borrow expressions, so we cannot create an `RValue` that // remains valid across user code. `as_rvalue` is usually called @@ -244,6 +255,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block.unit() } ExprKind::AddressOf { mutability, arg } => { + let arg = &this.thir[arg]; let place = match mutability { hir::Mutability::Not => this.as_read_only_place(block, arg), hir::Mutability::Mut => this.as_place(block, arg), @@ -252,7 +264,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.cfg.push_assign(block, source_info, destination, address_of); block.unit() } - ExprKind::Adt { adt_def, variant_index, substs, user_ty, fields, ref base } => { + ExprKind::Adt { adt_def, variant_index, substs, user_ty, ref fields, ref base } => { // See the notes for `ExprKind::Array` in `as_rvalue` and for // `ExprKind::Borrow` above. let is_union = adt_def.is_union(); @@ -264,19 +276,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // (evaluating them in order given by user) let fields_map: FxHashMap<_, _> = fields .into_iter() - .map(|f| (f.name, unpack!(block = this.as_operand(block, Some(scope), f.expr)))) + .map(|f| { + ( + f.name, + unpack!( + block = this.as_operand(block, Some(scope), &this.thir[f.expr]) + ), + ) + }) .collect(); let field_names: Vec<_> = (0..adt_def.variants[variant_index].fields.len()).map(Field::new).collect(); let fields: Vec<_> = if let Some(FruInfo { base, field_types }) = base { - let place_builder = unpack!(block = this.as_place_builder(block, base)); + let place_builder = + unpack!(block = this.as_place_builder(block, &this.thir[*base])); // MIR does not natively support FRU, so for each // base-supplied field, generate an operand that // reads it from the base. - iter::zip(field_names, *field_types) + iter::zip(field_names, &**field_types) .map(|(n, ty)| match fields_map.get(&n) { Some(v) => v.clone(), None => { @@ -316,27 +336,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); block.unit() } - ExprKind::InlineAsm { template, operands, options, line_spans } => { - use crate::thir; - use rustc_middle::mir; + ExprKind::InlineAsm { template, ref operands, options, line_spans } => { + use rustc_middle::{mir, thir}; let operands = operands .into_iter() .map(|op| match *op { thir::InlineAsmOperand::In { reg, expr } => mir::InlineAsmOperand::In { reg, - value: unpack!(block = this.as_local_operand(block, expr)), + value: unpack!(block = this.as_local_operand(block, &this.thir[expr])), }, thir::InlineAsmOperand::Out { reg, late, expr } => { mir::InlineAsmOperand::Out { reg, late, - place: expr - .as_ref() - .map(|expr| unpack!(block = this.as_place(block, expr))), + place: expr.map(|expr| { + unpack!(block = this.as_place(block, &this.thir[expr])) + }), } } thir::InlineAsmOperand::InOut { reg, late, expr } => { - let place = unpack!(block = this.as_place(block, expr)); + let place = unpack!(block = this.as_place(block, &this.thir[expr])); mir::InlineAsmOperand::InOut { reg, late, @@ -349,9 +368,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mir::InlineAsmOperand::InOut { reg, late, - in_value: unpack!(block = this.as_local_operand(block, in_expr)), - out_place: out_expr.as_ref().map(|out_expr| { - unpack!(block = this.as_place(block, out_expr)) + in_value: unpack!( + block = this.as_local_operand(block, &this.thir[in_expr]) + ), + out_place: out_expr.map(|out_expr| { + unpack!(block = this.as_place(block, &this.thir[out_expr])) }), } } @@ -360,9 +381,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { value: box Constant { span, user_ty: None, literal: value.into() }, } } - thir::InlineAsmOperand::SymFn { expr } => { - mir::InlineAsmOperand::SymFn { value: box this.as_constant(expr) } - } + thir::InlineAsmOperand::SymFn { expr } => mir::InlineAsmOperand::SymFn { + value: box this.as_constant(&this.thir[expr]), + }, thir::InlineAsmOperand::SymStatic { def_id } => { mir::InlineAsmOperand::SymStatic { def_id } } @@ -434,7 +455,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ExprKind::Yield { value } => { let scope = this.local_scope(); - let value = unpack!(block = this.as_operand(block, Some(scope), value)); + let value = unpack!(block = this.as_operand(block, Some(scope), &this.thir[value])); let resume = this.cfg.start_new_block(); this.cfg.terminate( block, diff --git a/compiler/rustc_mir_build/src/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs index f01315fc5db..b03a6bb1a2b 100644 --- a/compiler/rustc_mir_build/src/build/expr/stmt.rs +++ b/compiler/rustc_mir_build/src/build/expr/stmt.rs @@ -1,8 +1,8 @@ use crate::build::scope::BreakableTarget; use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder}; -use crate::thir::*; use rustc_middle::middle::region; use rustc_middle::mir::*; +use rustc_middle::thir::*; impl<'a, 'tcx> Builder<'a, 'tcx> { /// Builds a block of MIR statements to evaluate the THIR `expr`. @@ -13,7 +13,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn stmt_expr( &mut self, mut block: BasicBlock, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, statement_scope: Option<region::Scope>, ) -> BlockAnd<()> { let this = self; @@ -24,10 +24,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match expr.kind { ExprKind::Scope { region_scope, lint_level, value } => { this.in_scope((region_scope, source_info), lint_level, |this| { - this.stmt_expr(block, value, statement_scope) + this.stmt_expr(block, &this.thir[value], statement_scope) }) } ExprKind::Assign { lhs, rhs } => { + let lhs = &this.thir[lhs]; + let rhs = &this.thir[rhs]; let lhs_span = lhs.span; // Note: we evaluate assignments right-to-left. This @@ -61,6 +63,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // only affects weird things like `x += {x += 1; x}` // -- is that equal to `x + (x + 1)` or `2*(x+1)`? + let lhs = &this.thir[lhs]; + let rhs = &this.thir[rhs]; let lhs_ty = lhs.ty; debug!("stmt_expr AssignOp block_context.push(SubExpr) : {:?}", expr); @@ -87,24 +91,30 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } ExprKind::Break { label, value } => this.break_scope( block, - value.as_deref(), + value.map(|value| &this.thir[value]), BreakableTarget::Break(label), source_info, ), - ExprKind::Return { value } => { - this.break_scope(block, value.as_deref(), BreakableTarget::Return, source_info) - } - ExprKind::LlvmInlineAsm { asm, outputs, inputs } => { + ExprKind::Return { value } => this.break_scope( + block, + value.map(|value| &this.thir[value]), + BreakableTarget::Return, + source_info, + ), + ExprKind::LlvmInlineAsm { asm, ref outputs, ref inputs } => { debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr); this.block_context.push(BlockFrame::SubExpr); let outputs = outputs .into_iter() - .map(|output| unpack!(block = this.as_place(block, &output))) + .copied() + .map(|output| unpack!(block = this.as_place(block, &this.thir[output]))) .collect::<Vec<_>>() .into_boxed_slice(); let inputs = inputs .into_iter() + .copied() .map(|input| { + let input = &this.thir[input]; (input.span, unpack!(block = this.as_local_operand(block, &input))) }) .collect::<Vec<_>>() @@ -139,14 +149,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // than the entirety of block(s) surrounding it. let adjusted_span = (|| { if let ExprKind::Block { body } = &expr.kind { - if let Some(tail_expr) = &body.expr { - let mut expr = &*tail_expr; + if let Some(tail_expr) = body.expr { + let mut expr = &this.thir[tail_expr]; while let ExprKind::Block { body: Block { expr: Some(nested_expr), .. }, } - | ExprKind::Scope { value: nested_expr, .. } = &expr.kind + | ExprKind::Scope { value: nested_expr, .. } = expr.kind { - expr = nested_expr; + expr = &this.thir[nested_expr]; } this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored: true, diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 0e422dc3c63..8164529dd1f 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -10,7 +10,6 @@ use crate::build::scope::DropKind; use crate::build::ForGuard::{self, OutsideGuard, RefWithinGuard}; use crate::build::{BlockAnd, BlockAndExtension, Builder}; use crate::build::{GuardFrame, GuardFrameLocal, LocalsForNode}; -use crate::thir::{self, *}; use rustc_data_structures::{ fx::{FxHashSet, FxIndexMap}, stack::ensure_sufficient_stack, @@ -19,6 +18,7 @@ use rustc_hir::HirId; use rustc_index::bit_set::BitSet; use rustc_middle::middle::region; use rustc_middle::mir::*; +use rustc_middle::thir::{self, *}; use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty}; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -90,8 +90,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: Place<'tcx>, span: Span, mut block: BasicBlock, - scrutinee: &Expr<'_, 'tcx>, - arms: &[Arm<'_, 'tcx>], + scrutinee: &Expr<'tcx>, + arms: &[ArmId], ) -> BlockAnd<()> { let scrutinee_span = scrutinee.span; let scrutinee_place = @@ -99,7 +99,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().any(|arm| arm.guard.is_some()); + let match_has_guard = arms.iter().copied().any(|arm| self.thir[arm].guard.is_some()); let mut candidates = arm_candidates.iter_mut().map(|(_, candidate)| candidate).collect::<Vec<_>>(); @@ -120,7 +120,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn lower_scrutinee( &mut self, mut block: BasicBlock, - scrutinee: &Expr<'_, 'tcx>, + scrutinee: &Expr<'tcx>, scrutinee_span: Span, ) -> BlockAnd<PlaceBuilder<'tcx>> { let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee)); @@ -156,12 +156,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn create_match_candidates<'pat>( &mut self, scrutinee: PlaceBuilder<'tcx>, - arms: &'pat [Arm<'pat, 'tcx>], - ) -> Vec<(&'pat Arm<'pat, 'tcx>, Candidate<'pat, 'tcx>)> { + arms: &'pat [ArmId], + ) -> Vec<(&'pat Arm<'tcx>, Candidate<'pat, 'tcx>)> + where + 'a: 'pat, + { // Assemble a list of candidates: there is one candidate per pattern, // which means there may be more than one candidate *per arm*. arms.iter() + .copied() .map(|arm| { + let arm = &self.thir[arm]; let arm_has_guard = arm.guard.is_some(); let arm_candidate = Candidate::new(scrutinee.clone(), &arm.pattern, arm_has_guard); (arm, arm_candidate) @@ -231,7 +236,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { destination: Place<'tcx>, scrutinee_place_builder: PlaceBuilder<'tcx>, scrutinee_span: Span, - arm_candidates: Vec<(&'_ Arm<'_, 'tcx>, Candidate<'_, 'tcx>)>, + arm_candidates: Vec<(&'_ Arm<'tcx>, Candidate<'_, 'tcx>)>, outer_source_info: SourceInfo, fake_borrow_temps: Vec<(Place<'tcx>, Local)>, ) -> BlockAnd<()> { @@ -286,7 +291,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { this.source_scope = source_scope; } - this.expr_into_dest(destination, arm_block, &arm.body) + this.expr_into_dest(destination, arm_block, &&this.thir[arm.body]) }) }) .collect(); @@ -313,7 +318,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, outer_source_info: SourceInfo, candidate: Candidate<'_, 'tcx>, - guard: Option<&Guard<'_, 'tcx>>, + guard: Option<&Guard<'tcx>>, fake_borrow_temps: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, arm_span: Option<Span>, @@ -389,7 +394,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, mut block: BasicBlock, irrefutable_pat: Pat<'tcx>, - initializer: &Expr<'_, 'tcx>, + initializer: &Expr<'tcx>, ) -> BlockAnd<()> { match *irrefutable_pat.kind { // Optimize the case of `let x = ...` to write directly into `x` @@ -427,7 +432,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .. }, ascription: - thir::pattern::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span }, + thir::Ascription { user_ty: pat_ascription_ty, variance: _, user_ty_span }, } => { let place = self.storage_live_binding(block, var, irrefutable_pat.span, OutsideGuard, true); @@ -682,7 +687,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::AscribeUserType { ref subpattern, - ascription: thir::pattern::Ascription { ref user_ty, user_ty_span, variance: _ }, + ascription: thir::Ascription { ref user_ty, user_ty_span, variance: _ }, } => { // This corresponds to something like // @@ -1665,7 +1670,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &mut self, candidate: Candidate<'pat, 'tcx>, parent_bindings: &[(Vec<Binding<'tcx>>, Vec<Ascription<'tcx>>)], - guard: Option<&Guard<'_, 'tcx>>, + guard: Option<&Guard<'tcx>>, fake_borrows: &Vec<(Place<'tcx>, Local)>, scrutinee_span: Span, arm_span: Option<Span>, @@ -1799,12 +1804,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.cfg.push_assign(block, scrutinee_source_info, Place::from(temp), borrow); } - let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match guard { + let (guard_span, (post_guard_block, otherwise_post_guard_block)) = match *guard { Guard::If(e) => { + let e = &self.thir[e]; let source_info = self.source_info(e.span); (e.span, self.test_bool(block, e, source_info)) } - Guard::IfLet(pat, scrutinee) => { + Guard::IfLet(ref pat, scrutinee) => { + let scrutinee = &self.thir[scrutinee]; let scrutinee_span = scrutinee.span; let scrutinee_place_builder = unpack!(block = self.lower_scrutinee(block, scrutinee, scrutinee_span)); @@ -1840,7 +1847,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { guard_candidate, None, &fake_borrow_temps, - scrutinee.span, + scrutinee_span, None, None, ); diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index 3ad143a57ff..13cfc3695cc 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -15,8 +15,8 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::{Ascription, Binding, Candidate, MatchPair}; use crate::build::Builder; -use crate::thir::{self, *}; use rustc_hir::RangeEnd; +use rustc_middle::thir::{self, *}; use rustc_middle::ty; use rustc_middle::ty::layout::IntegerExt; use rustc_target::abi::{Integer, Size}; @@ -152,7 +152,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { match *match_pair.pattern.kind { PatKind::AscribeUserType { ref subpattern, - ascription: thir::pattern::Ascription { variance, user_ty, user_ty_span }, + ascription: thir::Ascription { variance, user_ty, user_ty_span }, } => { // Apply the type ascription to the value at `match_pair.place`, which is the candidate.ascriptions.push(Ascription { diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index b082169cd63..c87f42738c6 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -9,11 +9,11 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::{Candidate, MatchPair, Test, TestKind}; use crate::build::Builder; use crate::thir::pattern::compare_const_vals; -use crate::thir::*; use rustc_data_structures::fx::FxIndexMap; use rustc_hir::{LangItem, RangeEnd}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::*; +use rustc_middle::thir::*; use rustc_middle::ty::subst::{GenericArg, Subst}; use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index d49a00a5660..3cf8ae6efd9 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,8 +1,8 @@ use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::MatchPair; use crate::build::Builder; -use crate::thir::*; use rustc_middle::mir::*; +use rustc_middle::thir::*; use rustc_middle::ty; use smallvec::SmallVec; use std::convert::TryInto; diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index f944e5f8f04..10d6521e7de 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -1,7 +1,7 @@ use crate::build; use crate::build::expr::as_place::PlaceBuilder; use crate::build::scope::DropKind; -use crate::thir::{build_thir, Arena, BindingMode, Expr, LintLevel, Pat, PatKind}; +use crate::thir::pattern::pat_from_hir; use rustc_attr::{self as attr, UnwindAttr}; use rustc_errors::ErrorReported; use rustc_hir as hir; @@ -13,6 +13,7 @@ use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::middle::region; use rustc_middle::mir::*; +use rustc_middle::thir::{BindingMode, Expr, ExprId, LintLevel, PatKind, Thir}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeckResults}; use rustc_span::symbol::{kw, sym}; @@ -45,6 +46,16 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ let body_owner_kind = tcx.hir().body_owner_kind(id); let typeck_results = tcx.typeck_opt_const_arg(def); + // Ensure unsafeck is ran before we steal the THIR. + match def { + ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => { + tcx.ensure().thir_check_unsafety_for_const_arg((did, const_param_did)) + } + ty::WithOptConstParam { did, const_param_did: None } => { + tcx.ensure().thir_check_unsafety(did) + } + } + // Figure out what primary body this item has. let (body_id, return_ty_span, span_with_body) = match tcx.hir().get(id) { Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(_, decl, body_id, _, _), .. }) => { @@ -88,7 +99,6 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ // If we don't have a specialized span for the body, just use the // normal def span. let span_with_body = span_with_body.unwrap_or_else(|| tcx.hir().span(id)); - let arena = Arena::default(); tcx.infer_ctxt().enter(|infcx| { let body = if let Some(ErrorReported) = typeck_results.tainted_by_errors { @@ -105,7 +115,10 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ }; let body = tcx.hir().body(body_id); - let thir = build_thir(tcx, def, &arena, &body.value); + let (thir, expr) = tcx.thir_body(def); + // We ran all queries that depended on THIR at the beginning + // of `mir_build`, so now we can steal it + let thir = thir.steal(); let ty = tcx.type_of(fn_def_id); let mut abi = fn_sig.abi; let implicit_argument = match ty.kind() { @@ -181,6 +194,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ }; let mut mir = build::construct_fn( + &thir, &infcx, def, id, @@ -190,7 +204,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ return_ty, return_ty_span, body, - thir, + expr, span_with_body, ); if yield_ty.is_some() { @@ -212,10 +226,12 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_ let return_ty = typeck_results.node_type(id); - let ast_expr = &tcx.hir().body(body_id).value; - let thir = build_thir(tcx, def, &arena, ast_expr); + let (thir, expr) = tcx.thir_body(def); + // We ran all queries that depended on THIR at the beginning + // of `mir_build`, so now we can steal it + let thir = thir.steal(); - build::construct_const(&infcx, thir, def, id, return_ty, return_ty_span) + build::construct_const(&thir, &infcx, expr, def, id, return_ty, return_ty_span) }; lints::check(tcx, &body); @@ -323,6 +339,7 @@ struct Builder<'a, 'tcx> { region_scope_tree: &'tcx region::ScopeTree, param_env: ty::ParamEnv<'tcx>, + thir: &'a Thir<'tcx>, cfg: CFG<'tcx>, def_id: DefId, @@ -633,6 +650,7 @@ struct ArgInfo<'tcx>( ); fn construct_fn<'tcx, A>( + thir: &Thir<'tcx>, infcx: &InferCtxt<'_, 'tcx>, fn_def: ty::WithOptConstParam<LocalDefId>, fn_id: hir::HirId, @@ -642,7 +660,7 @@ fn construct_fn<'tcx, A>( return_ty: Ty<'tcx>, return_ty_span: Span, body: &'tcx hir::Body<'tcx>, - expr: &Expr<'_, 'tcx>, + expr: ExprId, span_with_body: Span, ) -> Body<'tcx> where @@ -654,6 +672,7 @@ where let span = tcx.hir().span(fn_id); let mut builder = Builder::new( + thir, infcx, fn_def, fn_id, @@ -683,7 +702,7 @@ where fn_def.did.to_def_id(), &arguments, arg_scope, - expr, + &thir[expr], ) })) })); @@ -708,8 +727,9 @@ where } fn construct_const<'a, 'tcx>( + thir: &'a Thir<'tcx>, infcx: &'a InferCtxt<'a, 'tcx>, - expr: &Expr<'_, 'tcx>, + expr: ExprId, def: ty::WithOptConstParam<LocalDefId>, hir_id: hir::HirId, const_ty: Ty<'tcx>, @@ -717,11 +737,21 @@ fn construct_const<'a, 'tcx>( ) -> Body<'tcx> { let tcx = infcx.tcx; let span = tcx.hir().span(hir_id); - let mut builder = - Builder::new(infcx, def, hir_id, span, 0, Safety::Safe, const_ty, const_ty_span, None); + let mut builder = Builder::new( + thir, + infcx, + def, + hir_id, + span, + 0, + Safety::Safe, + const_ty, + const_ty_span, + None, + ); let mut block = START_BLOCK; - unpack!(block = builder.expr_into_dest(Place::return_place(), block, &expr)); + unpack!(block = builder.expr_into_dest(Place::return_place(), block, &thir[expr])); let source_info = builder.source_info(span); builder.cfg.terminate(block, source_info, TerminatorKind::Return); @@ -761,22 +791,48 @@ fn construct_error<'a, 'tcx>( hir::BodyOwnerKind::Const => 0, hir::BodyOwnerKind::Static(_) => 0, }; - let mut builder = - Builder::new(infcx, def, hir_id, span, num_params, Safety::Safe, ty, span, generator_kind); - let source_info = builder.source_info(span); + let mut cfg = CFG { basic_blocks: IndexVec::new() }; + let mut source_scopes = IndexVec::new(); + let mut local_decls = IndexVec::from_elem_n(LocalDecl::new(ty, span), 1); + + cfg.start_new_block(); + source_scopes.push(SourceScopeData { + span, + parent_scope: None, + inlined: None, + inlined_parent_scope: None, + local_data: ClearCrossCrate::Set(SourceScopeLocalData { + lint_root: hir_id, + safety: Safety::Safe, + }), + }); + let source_info = SourceInfo { span, scope: OUTERMOST_SOURCE_SCOPE }; + // Some MIR passes will expect the number of parameters to match the // function declaration. for _ in 0..num_params { - builder.local_decls.push(LocalDecl::with_source_info(ty, source_info)); + local_decls.push(LocalDecl::with_source_info(ty, source_info)); } - builder.cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); - let mut body = builder.finish(); + cfg.terminate(START_BLOCK, source_info, TerminatorKind::Unreachable); + + let mut body = Body::new( + MirSource::item(def.did.to_def_id()), + cfg.basic_blocks, + source_scopes, + local_decls, + IndexVec::new(), + num_params, + vec![], + span, + generator_kind, + ); body.generator.as_mut().map(|gen| gen.yield_ty = Some(ty)); body } impl<'a, 'tcx> Builder<'a, 'tcx> { fn new( + thir: &'a Thir<'tcx>, infcx: &'a InferCtxt<'a, 'tcx>, def: ty::WithOptConstParam<LocalDefId>, hir_id: hir::HirId, @@ -803,6 +859,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let lint_level = LintLevel::Explicit(hir_id); let mut builder = Builder { + thir, tcx, infcx, typeck_results: tcx.typeck_opt_const_arg(def), @@ -866,7 +923,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { fn_def_id: DefId, arguments: &[ArgInfo<'tcx>], argument_scope: region::Scope, - expr: &Expr<'_, 'tcx>, + expr: &Expr<'tcx>, ) -> BlockAnd<()> { // Allocate locals for the function arguments for &ArgInfo(ty, _, arg_opt, _) in arguments.iter() { @@ -896,9 +953,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // the given closure and use the necessary information to create upvar // debuginfo and to fill `self.upvar_mutbls`. if hir_typeck_results.closure_min_captures.get(&fn_def_id).is_some() { - let closure_env_arg = Local::new(1); let mut closure_env_projs = vec![]; - let mut closure_ty = self.local_decls[closure_env_arg].ty; + let mut closure_ty = self.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty; if let ty::Ref(_, ty, _) = closure_ty.kind() { closure_env_projs.push(ProjectionElem::Deref); closure_ty = ty; @@ -944,7 +1000,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { name, source_info: SourceInfo::outermost(tcx_hir.span(var_id)), value: VarDebugInfoContents::Place(Place { - local: closure_env_arg, + local: ty::CAPTURE_STRUCT_LOCAL, projection: tcx.intern_place_elems(&projs), }), }); @@ -975,7 +1031,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { Node::Pat(pat) | Node::Binding(pat) => pat, node => bug!("pattern became {:?}", node), }; - let pattern = Pat::from_hir(tcx, self.param_env, self.typeck_results, pat); + let pattern = pat_from_hir(tcx, self.param_env, self.typeck_results, pat); let original_source_scope = self.source_scope; let span = pattern.span; self.set_correct_source_scope_for_arg(arg.hir_id, original_source_scope, span); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 41fc925c049..3de894bd370 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -82,11 +82,12 @@ that contains only loops and breakable blocks. It tracks where a `break`, */ use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG}; -use crate::thir::{Expr, LintLevel}; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::IndexVec; use rustc_middle::middle::region; use rustc_middle::mir::*; +use rustc_middle::thir::{Expr, LintLevel}; + use rustc_span::{Span, DUMMY_SP}; #[derive(Debug)] @@ -574,7 +575,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn break_scope( &mut self, mut block: BasicBlock, - value: Option<&Expr<'_, 'tcx>>, + value: Option<&Expr<'tcx>>, target: BreakableTarget, source_info: SourceInfo, ) -> BlockAnd<()> { @@ -933,7 +934,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { crate fn test_bool( &mut self, mut block: BasicBlock, - condition: &Expr<'_, 'tcx>, + condition: &Expr<'tcx>, source_info: SourceInfo, ) -> (BasicBlock, BasicBlock) { let cond = unpack!(block = self.as_local_operand(block, condition)); diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 83288fa541e..2d52577829c 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -1,16 +1,20 @@ use crate::thir::visit::{self, Visitor}; -use crate::thir::*; use rustc_errors::struct_span_err; use rustc_hir as hir; +use rustc_middle::thir::*; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_session::lint::Level; use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::symbol::Symbol; use rustc_span::Span; -struct UnsafetyVisitor<'tcx> { +use std::ops::Bound; + +struct UnsafetyVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, + thir: &'a Thir<'tcx>, /// The `HirId` of the current scope, which would be the `HirId` /// of the current HIR node, modulo adjustments. Used for lint levels. hir_context: hir::HirId, @@ -18,9 +22,13 @@ struct UnsafetyVisitor<'tcx> { /// `unsafe` block, and whether it has been used. safety_context: SafetyContext, body_unsafety: BodyUnsafety, + /// The `#[target_feature]` attributes of the body. Used for checking + /// calls to functions with `#[target_feature]` (RFC 2396). + body_target_features: &'tcx Vec<Symbol>, + is_const: bool, } -impl<'tcx> UnsafetyVisitor<'tcx> { +impl<'tcx> UnsafetyVisitor<'_, 'tcx> { fn in_safety_context<R>( &mut self, safety_context: SafetyContext, @@ -34,7 +42,7 @@ impl<'tcx> UnsafetyVisitor<'tcx> { self.warn_unused_unsafe( hir_id, block_span, - Some(self.tcx.sess.source_map().guess_head_span(enclosing_span)), + Some((self.tcx.sess.source_map().guess_head_span(enclosing_span), "block")), ); f(self); } else { @@ -44,7 +52,15 @@ impl<'tcx> UnsafetyVisitor<'tcx> { f(self); if let SafetyContext::UnsafeBlock { used: false, span, hir_id } = self.safety_context { - self.warn_unused_unsafe(hir_id, span, self.body_unsafety.unsafe_fn_sig_span()); + self.warn_unused_unsafe( + hir_id, + span, + if self.unsafe_op_in_unsafe_fn_allowed() { + self.body_unsafety.unsafe_fn_sig_span().map(|span| (span, "fn")) + } else { + None + }, + ); } self.safety_context = prev_context; return; @@ -64,38 +80,34 @@ impl<'tcx> UnsafetyVisitor<'tcx> { SafetyContext::UnsafeFn if unsafe_op_in_unsafe_fn_allowed => {} SafetyContext::UnsafeFn => { // unsafe_op_in_unsafe_fn is disallowed - if kind == BorrowOfPackedField { - // FIXME handle borrows of packed fields - } else { - struct_span_err!( - self.tcx.sess, - span, - E0133, - "{} is unsafe and requires unsafe block", - description, - ) - .span_label(span, description) - .note(note) - .emit(); - } + self.tcx.struct_span_lint_hir( + UNSAFE_OP_IN_UNSAFE_FN, + self.hir_context, + span, + |lint| { + lint.build(&format!( + "{} is unsafe and requires unsafe block (error E0133)", + description, + )) + .span_label(span, description) + .note(note) + .emit(); + }, + ) } SafetyContext::Safe => { - if kind == BorrowOfPackedField { - // FIXME handle borrows of packed fields - } else { - let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" }; - struct_span_err!( - self.tcx.sess, - span, - E0133, - "{} is unsafe and requires unsafe{} block", - description, - fn_sugg, - ) - .span_label(span, description) - .note(note) - .emit(); - } + let fn_sugg = if unsafe_op_in_unsafe_fn_allowed { " function or" } else { "" }; + struct_span_err!( + self.tcx.sess, + span, + E0133, + "{} is unsafe and requires unsafe{} block", + description, + fn_sugg, + ) + .span_label(span, description) + .note(note) + .emit(); } } } @@ -104,18 +116,15 @@ impl<'tcx> UnsafetyVisitor<'tcx> { &self, hir_id: hir::HirId, block_span: Span, - enclosing_span: Option<Span>, + enclosing_unsafe: Option<(Span, &'static str)>, ) { let block_span = self.tcx.sess.source_map().guess_head_span(block_span); self.tcx.struct_span_lint_hir(UNUSED_UNSAFE, hir_id, block_span, |lint| { let msg = "unnecessary `unsafe` block"; let mut db = lint.build(msg); db.span_label(block_span, msg); - if let Some(enclosing_span) = enclosing_span { - db.span_label( - enclosing_span, - format!("because it's nested under this `unsafe` block"), - ); + if let Some((span, kind)) = enclosing_unsafe { + db.span_label(span, format!("because it's nested under this `unsafe` {}", kind)); } db.emit(); }); @@ -127,8 +136,12 @@ impl<'tcx> UnsafetyVisitor<'tcx> { } } -impl<'thir, 'tcx> Visitor<'thir, 'tcx> for UnsafetyVisitor<'tcx> { - fn visit_block(&mut self, block: &Block<'thir, 'tcx>) { +impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> { + fn thir(&self) -> &'a Thir<'tcx> { + &self.thir + } + + fn visit_block(&mut self, block: &Block) { if let BlockSafety::ExplicitUnsafe(hir_id) = block.safety_mode { self.in_safety_context( SafetyContext::UnsafeBlock { span: block.span, hir_id, used: false }, @@ -139,23 +152,94 @@ impl<'thir, 'tcx> Visitor<'thir, 'tcx> for UnsafetyVisitor<'tcx> { } } - fn visit_expr(&mut self, expr: &'thir Expr<'thir, 'tcx>) { + fn visit_expr(&mut self, expr: &Expr<'tcx>) { match expr.kind { ExprKind::Scope { value, lint_level: LintLevel::Explicit(hir_id), region_scope: _ } => { let prev_id = self.hir_context; self.hir_context = hir_id; - self.visit_expr(value); + self.visit_expr(&self.thir[value]); self.hir_context = prev_id; return; } ExprKind::Call { fun, ty: _, args: _, from_hir_call: _, fn_span: _ } => { - if fun.ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe { + if self.thir[fun].ty.fn_sig(self.tcx).unsafety() == hir::Unsafety::Unsafe { self.requires_unsafe(expr.span, CallToUnsafeFunction); + } else if let &ty::FnDef(func_did, _) = self.thir[fun].ty.kind() { + // If the called function has target features the calling function hasn't, + // the call requires `unsafe`. Don't check this on wasm + // targets, though. For more information on wasm see the + // is_like_wasm check in typeck/src/collect.rs + if !self.tcx.sess.target.options.is_like_wasm + && !self + .tcx + .codegen_fn_attrs(func_did) + .target_features + .iter() + .all(|feature| self.body_target_features.contains(feature)) + { + self.requires_unsafe(expr.span, CallToFunctionWith); + } + } + } + ExprKind::Deref { arg } => { + if let ExprKind::StaticRef { def_id, .. } = self.thir[arg].kind { + if self.tcx.is_mutable_static(def_id) { + self.requires_unsafe(expr.span, UseOfMutableStatic); + } else if self.tcx.is_foreign_item(def_id) { + self.requires_unsafe(expr.span, UseOfExternStatic); + } + } else if self.thir[arg].ty.is_unsafe_ptr() { + self.requires_unsafe(expr.span, DerefOfRawPointer); } } ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => { self.requires_unsafe(expr.span, UseOfInlineAssembly); } + ExprKind::Adt { + adt_def, + variant_index: _, + substs: _, + user_ty: _, + fields: _, + base: _, + } => match self.tcx.layout_scalar_valid_range(adt_def.did) { + (Bound::Unbounded, Bound::Unbounded) => {} + _ => self.requires_unsafe(expr.span, InitializingTypeWith), + }, + ExprKind::Cast { source } => { + let source = &self.thir[source]; + if self.tcx.features().const_raw_ptr_to_usize_cast + && self.is_const + && (source.ty.is_unsafe_ptr() || source.ty.is_fn_ptr()) + && expr.ty.is_integral() + { + self.requires_unsafe(expr.span, CastOfPointerToInt); + } + } + ExprKind::Closure { + closure_id, + substs: _, + upvars: _, + movability: _, + fake_reads: _, + } => { + let closure_id = closure_id.expect_local(); + let closure_def = if let Some((did, const_param_id)) = + ty::WithOptConstParam::try_lookup(closure_id, self.tcx) + { + ty::WithOptConstParam { did, const_param_did: Some(const_param_id) } + } else { + ty::WithOptConstParam::unknown(closure_id) + }; + let (closure_thir, expr) = self.tcx.thir_body(closure_def); + let closure_thir = &closure_thir.borrow(); + let hir_context = self.tcx.hir().local_def_id_to_hir_id(closure_id); + let mut closure_visitor = + UnsafetyVisitor { thir: closure_thir, hir_context, ..*self }; + closure_visitor.visit_expr(&closure_thir[expr]); + // Unsafe blocks can be used in closures, make sure to take it into account + self.safety_context = closure_visitor.safety_context; + } _ => {} } @@ -198,17 +282,10 @@ impl BodyUnsafety { enum UnsafeOpKind { CallToUnsafeFunction, UseOfInlineAssembly, - #[allow(dead_code)] // FIXME InitializingTypeWith, - #[allow(dead_code)] // FIXME CastOfPointerToInt, - #[allow(dead_code)] // FIXME - BorrowOfPackedField, - #[allow(dead_code)] // FIXME UseOfMutableStatic, - #[allow(dead_code)] // FIXME UseOfExternStatic, - #[allow(dead_code)] // FIXME DerefOfRawPointer, #[allow(dead_code)] // FIXME AssignToDroppingUnionField, @@ -218,7 +295,6 @@ enum UnsafeOpKind { MutationOfLayoutConstrainedField, #[allow(dead_code)] // FIXME BorrowOfLayoutConstrainedField, - #[allow(dead_code)] // FIXME CallToFunctionWith, } @@ -244,11 +320,6 @@ impl UnsafeOpKind { CastOfPointerToInt => { ("cast of pointer to int", "casting pointers to integers in constants") } - BorrowOfPackedField => ( - "borrow of packed field", - "fields of packed structs might be misaligned: dereferencing a misaligned pointer \ - or even just creating a misaligned reference is undefined behavior", - ), UseOfMutableStatic => ( "use of mutable static", "mutable statics can be mutated by multiple threads: aliasing violations or data \ @@ -261,7 +332,7 @@ impl UnsafeOpKind { ), DerefOfRawPointer => ( "dereference of raw pointer", - "raw pointers may be NULL, dangling or unaligned; they can violate aliasing rules \ + "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \ and cause data races: all of these are undefined behavior", ), AssignToDroppingUnionField => ( @@ -291,9 +362,26 @@ impl UnsafeOpKind { } } -// FIXME: checking unsafety for closures should be handled by their parent body, -// as they inherit their "safety context" from their declaration site. -pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, thir: &Expr<'_, 'tcx>, hir_id: hir::HirId) { +pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) { + // THIR unsafeck is gated under `-Z thir-unsafeck` + if !tcx.sess.opts.debugging_opts.thir_unsafeck { + return; + } + + // Closures are handled by their parent function + if tcx.is_closure(def.did.to_def_id()) { + tcx.ensure().thir_check_unsafety(tcx.hir().local_def_id_to_hir_id(def.did).owner); + return; + } + + let (thir, expr) = tcx.thir_body(def); + let thir = &thir.borrow(); + // If `thir` is empty, a type error occured, skip this body. + if thir.exprs.is_empty() { + return; + } + + let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| { if fn_sig.header.unsafety == hir::Unsafety::Unsafe { BodyUnsafety::Unsafe(fn_sig.span) @@ -301,30 +389,31 @@ pub fn check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, thir: &Expr<'_, 'tcx>, hir_id: hi BodyUnsafety::Safe } }); + let body_target_features = &tcx.codegen_fn_attrs(def.did).target_features; let safety_context = if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe }; - let mut visitor = UnsafetyVisitor { tcx, safety_context, hir_context: hir_id, body_unsafety }; - visitor.visit_expr(thir); -} - -crate fn thir_check_unsafety_inner<'tcx>( - tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam<LocalDefId>, -) { - let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - let body_id = tcx.hir().body_owned_by(hir_id); - let body = tcx.hir().body(body_id); - - let arena = Arena::default(); - let thir = cx::build_thir(tcx, def, &arena, &body.value); - check_unsafety(tcx, thir, hir_id); + let is_const = match tcx.hir().body_owner_kind(hir_id) { + hir::BodyOwnerKind::Closure => false, + hir::BodyOwnerKind::Fn => tcx.is_const_fn_raw(def.did.to_def_id()), + hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_) => true, + }; + let mut visitor = UnsafetyVisitor { + tcx, + thir, + safety_context, + hir_context: hir_id, + body_unsafety, + body_target_features, + is_const, + }; + visitor.visit_expr(&thir[expr]); } crate fn thir_check_unsafety<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) { if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) { tcx.thir_check_unsafety_for_const_arg(def) } else { - thir_check_unsafety_inner(tcx, ty::WithOptConstParam::unknown(def_id)) + check_unsafety(tcx, ty::WithOptConstParam::unknown(def_id)) } } @@ -332,5 +421,5 @@ crate fn thir_check_unsafety_for_const_arg<'tcx>( tcx: TyCtxt<'tcx>, (did, param_did): (LocalDefId, DefId), ) { - thir_check_unsafety_inner(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) + check_unsafety(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) }) } diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index d4e9a0a3169..d2992f0bf18 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -1,16 +1,14 @@ //! Construction of MIR from HIR. //! //! This crate also contains the match exhaustiveness and usefulness checking. -#![feature(array_windows)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(const_panic)] #![feature(control_flow_enum)] #![feature(crate_visibility_modifier)] #![feature(bool_to_option)] #![feature(iter_zip)] #![feature(once_cell)] -#![cfg_attr(bootstrap, feature(or_patterns))] +#![feature(min_specialization)] #![recursion_limit = "256"] #[macro_use] @@ -31,4 +29,5 @@ pub fn provide(providers: &mut Providers) { providers.mir_built = build::mir_built; providers.thir_check_unsafety = check_unsafety::thir_check_unsafety; providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg; + providers.thir_body = thir::cx::thir_body; } diff --git a/compiler/rustc_mir_build/src/thir/arena.rs b/compiler/rustc_mir_build/src/thir/arena.rs deleted file mode 100644 index aacc7b12a42..00000000000 --- a/compiler/rustc_mir_build/src/thir/arena.rs +++ /dev/null @@ -1,98 +0,0 @@ -use crate::thir::*; - -macro_rules! declare_arena { - ([], [$($a:tt $name:ident: $ty:ty,)*]) => { - #[derive(Default)] - pub struct Arena<'thir, 'tcx> { - pub dropless: rustc_arena::DroplessArena, - drop: rustc_arena::DropArena, - $($name: rustc_arena::arena_for_type!($a[$ty]),)* - } - - pub trait ArenaAllocatable<'thir, 'tcx, T = Self>: Sized { - fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self; - fn allocate_from_iter( - arena: &'thir Arena<'thir, 'tcx>, - iter: impl ::std::iter::IntoIterator<Item = Self>, - ) -> &'thir mut [Self]; - } - - impl<'thir, 'tcx, T: Copy> ArenaAllocatable<'thir, 'tcx, ()> for T { - #[inline] - fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self { - arena.dropless.alloc(self) - } - #[inline] - fn allocate_from_iter( - arena: &'thir Arena<'thir, 'tcx>, - iter: impl ::std::iter::IntoIterator<Item = Self>, - ) -> &'thir mut [Self] { - arena.dropless.alloc_from_iter(iter) - } - - } - $( - impl<'thir, 'tcx> ArenaAllocatable<'thir, 'tcx, $ty> for $ty { - #[inline] - fn allocate_on(self, arena: &'thir Arena<'thir, 'tcx>) -> &'thir mut Self { - if !::std::mem::needs_drop::<Self>() { - return arena.dropless.alloc(self); - } - match rustc_arena::which_arena_for_type!($a[&arena.$name]) { - ::std::option::Option::<&rustc_arena::TypedArena<Self>>::Some(ty_arena) => { - ty_arena.alloc(self) - } - ::std::option::Option::None => unsafe { arena.drop.alloc(self) }, - } - } - - #[inline] - fn allocate_from_iter( - arena: &'thir Arena<'thir, 'tcx>, - iter: impl ::std::iter::IntoIterator<Item = Self>, - ) -> &'thir mut [Self] { - if !::std::mem::needs_drop::<Self>() { - return arena.dropless.alloc_from_iter(iter); - } - match rustc_arena::which_arena_for_type!($a[&arena.$name]) { - ::std::option::Option::<&rustc_arena::TypedArena<Self>>::Some(ty_arena) => { - ty_arena.alloc_from_iter(iter) - } - ::std::option::Option::None => unsafe { arena.drop.alloc_from_iter(iter) }, - } - } - } - )* - - impl<'thir, 'tcx> Arena<'thir, 'tcx> { - #[inline] - pub fn alloc<T: ArenaAllocatable<'thir, 'tcx, U>, U>(&'thir self, value: T) -> &'thir mut T { - value.allocate_on(self) - } - - #[allow(dead_code)] // function is never used - #[inline] - pub fn alloc_slice<T: ::std::marker::Copy>(&'thir self, value: &[T]) -> &'thir mut [T] { - if value.is_empty() { - return &mut []; - } - self.dropless.alloc_slice(value) - } - - pub fn alloc_from_iter<T: ArenaAllocatable<'thir, 'tcx, U>, U>( - &'thir self, - iter: impl ::std::iter::IntoIterator<Item = T>, - ) -> &'thir mut [T] { - T::allocate_from_iter(self, iter) - } - } - } -} - -declare_arena!([], [ - [] arm: Arm<'thir, 'tcx>, - [] expr: Expr<'thir, 'tcx>, - [] field_expr: FieldExpr<'thir, 'tcx>, - [few] inline_asm_operand: InlineAsmOperand<'thir, 'tcx>, - [] stmt: Stmt<'thir, 'tcx>, -]); diff --git a/compiler/rustc_mir_build/src/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs index ac93d042970..d62fd161e2f 100644 --- a/compiler/rustc_mir_build/src/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -25,14 +25,14 @@ crate fn lit_to_const<'tcx>( let lit = match (lit, &ty.kind()) { (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { let s = s.as_str(); - let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes()); + let allocation = Allocation::from_bytes_byte_aligned_immutable(s.as_bytes()); let allocation = tcx.intern_const_alloc(allocation); ConstValue::Slice { data: allocation, start: 0, end: s.len() } } (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Slice(_)) => { - let allocation = Allocation::from_byte_aligned_bytes(data as &[u8]); + let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]); let allocation = tcx.intern_const_alloc(allocation); ConstValue::Slice { data: allocation, start: 0, end: data.len() } } diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs index d450f8a265d..77235fe9ab3 100644 --- a/compiler/rustc_mir_build/src/thir/cx/block.rs +++ b/compiler/rustc_mir_build/src/thir/cx/block.rs @@ -1,14 +1,14 @@ use crate::thir::cx::Cx; -use crate::thir::{self, *}; use rustc_hir as hir; use rustc_middle::middle::region; +use rustc_middle::thir::*; use rustc_middle::ty; use rustc_index::vec::Idx; -impl<'thir, 'tcx> Cx<'thir, 'tcx> { - crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block<'thir, 'tcx> { +impl<'tcx> Cx<'tcx> { + crate fn mirror_block(&mut self, block: &'tcx hir::Block<'tcx>) -> Block { // We have to eagerly lower the "spine" of the statements // in order to get the lexical scoping correctly. let stmts = self.mirror_stmts(block.hir_id.local_id, block.stmts); @@ -37,65 +37,78 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { &mut self, block_id: hir::ItemLocalId, stmts: &'tcx [hir::Stmt<'tcx>], - ) -> &'thir [Stmt<'thir, 'tcx>] { - self.arena.alloc_from_iter(stmts.iter().enumerate().filter_map(|(index, stmt)| { - let hir_id = stmt.hir_id; - let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id); - match stmt.kind { - hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => Some(Stmt { - kind: StmtKind::Expr { - scope: region::Scope { id: hir_id.local_id, data: region::ScopeData::Node }, - expr: self.mirror_expr(expr), - }, - opt_destruction_scope: opt_dxn_ext, - }), - hir::StmtKind::Item(..) => { - // ignore for purposes of the MIR - None - } - hir::StmtKind::Local(ref local) => { - let remainder_scope = region::Scope { - id: block_id, - data: region::ScopeData::Remainder(region::FirstStatementIndex::new(index)), - }; + ) -> Box<[StmtId]> { + stmts + .iter() + .enumerate() + .filter_map(|(index, stmt)| { + let hir_id = stmt.hir_id; + let opt_dxn_ext = self.region_scope_tree.opt_destruction_scope(hir_id.local_id); + match stmt.kind { + hir::StmtKind::Expr(ref expr) | hir::StmtKind::Semi(ref expr) => { + let stmt = Stmt { + kind: StmtKind::Expr { + scope: region::Scope { + id: hir_id.local_id, + data: region::ScopeData::Node, + }, + expr: self.mirror_expr(expr), + }, + opt_destruction_scope: opt_dxn_ext, + }; + Some(self.thir.stmts.push(stmt)) + } + hir::StmtKind::Item(..) => { + // ignore for purposes of the MIR + None + } + hir::StmtKind::Local(ref local) => { + let remainder_scope = region::Scope { + id: block_id, + data: region::ScopeData::Remainder(region::FirstStatementIndex::new( + index, + )), + }; - let mut pattern = self.pattern_from_hir(local.pat); + let mut pattern = self.pattern_from_hir(local.pat); - if let Some(ty) = &local.ty { - if let Some(&user_ty) = - self.typeck_results.user_provided_types().get(ty.hir_id) - { - debug!("mirror_stmts: user_ty={:?}", user_ty); - pattern = Pat { - ty: pattern.ty, - span: pattern.span, - kind: Box::new(PatKind::AscribeUserType { - ascription: thir::pattern::Ascription { - user_ty: PatTyProj::from_user_type(user_ty), - user_ty_span: ty.span, - variance: ty::Variance::Covariant, - }, - subpattern: pattern, - }), - }; + if let Some(ty) = &local.ty { + if let Some(&user_ty) = + self.typeck_results.user_provided_types().get(ty.hir_id) + { + debug!("mirror_stmts: user_ty={:?}", user_ty); + pattern = Pat { + ty: pattern.ty, + span: pattern.span, + kind: Box::new(PatKind::AscribeUserType { + ascription: Ascription { + user_ty: PatTyProj::from_user_type(user_ty), + user_ty_span: ty.span, + variance: ty::Variance::Covariant, + }, + subpattern: pattern, + }), + }; + } } - } - Some(Stmt { - kind: StmtKind::Let { - remainder_scope, - init_scope: region::Scope { - id: hir_id.local_id, - data: region::ScopeData::Node, + let stmt = Stmt { + kind: StmtKind::Let { + remainder_scope, + init_scope: region::Scope { + id: hir_id.local_id, + data: region::ScopeData::Node, + }, + pattern, + initializer: local.init.map(|init| self.mirror_expr(init)), + lint_level: LintLevel::Explicit(local.hir_id), }, - pattern, - initializer: local.init.map(|init| self.mirror_expr(init)), - lint_level: LintLevel::Explicit(local.hir_id), - }, - opt_destruction_scope: opt_dxn_ext, - }) + opt_destruction_scope: opt_dxn_ext, + }; + Some(self.thir.stmts.push(stmt)) + } } - } - })) + }) + .collect() } } diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 924278e1a7f..aa4acfab5c8 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -1,6 +1,5 @@ use crate::thir::cx::Cx; use crate::thir::util::UserAnnotatedTyHelpers; -use crate::thir::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; @@ -8,43 +7,30 @@ use rustc_index::vec::Idx; use rustc_middle::hir::place::Place as HirPlace; use rustc_middle::hir::place::PlaceBase as HirPlaceBase; use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; +use rustc_middle::middle::region; use rustc_middle::mir::interpret::Scalar; -use rustc_middle::mir::BorrowKind; +use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp}; +use rustc_middle::thir::*; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AutoBorrow, AutoBorrowMutability, PointerCast, }; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; -use rustc_middle::ty::{self, AdtKind, Ty}; +use rustc_middle::ty::{self, AdtKind, Ty, UpvarSubsts, UserType}; +use rustc_span::def_id::DefId; use rustc_span::Span; +use rustc_target::abi::VariantIdx; -use std::iter; - -impl<'thir, 'tcx> Cx<'thir, 'tcx> { - /// Mirrors and allocates a single [`hir::Expr`]. If you need to mirror a whole slice - /// of expressions, prefer using [`mirror_exprs`]. - /// - /// [`mirror_exprs`]: Self::mirror_exprs - crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> &'thir Expr<'thir, 'tcx> { +impl<'tcx> Cx<'tcx> { + crate fn mirror_expr(&mut self, expr: &'tcx hir::Expr<'tcx>) -> ExprId { // `mirror_expr` is recursing very deep. Make sure the stack doesn't overflow. - ensure_sufficient_stack(|| self.arena.alloc(self.mirror_expr_inner(expr))) + ensure_sufficient_stack(|| self.mirror_expr_inner(expr)) } - /// Mirrors and allocates a slice of [`hir::Expr`]s. They will be allocated as a - /// contiguous sequence in memory. - crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> &'thir [Expr<'thir, 'tcx>] { - self.arena.alloc_from_iter(exprs.iter().map(|expr| self.mirror_expr_inner(expr))) + crate fn mirror_exprs(&mut self, exprs: &'tcx [hir::Expr<'tcx>]) -> Box<[ExprId]> { + exprs.iter().map(|expr| self.mirror_expr_inner(expr)).collect() } - /// Mirrors a [`hir::Expr`] without allocating it into the arena. - /// This is a separate, private function so that [`mirror_expr`] and [`mirror_exprs`] can - /// decide how to allocate this expression (alone or within a slice). - /// - /// [`mirror_expr`]: Self::mirror_expr - /// [`mirror_exprs`]: Self::mirror_exprs - pub(super) fn mirror_expr_inner( - &mut self, - hir_expr: &'tcx hir::Expr<'tcx>, - ) -> Expr<'thir, 'tcx> { + pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> ExprId { let temp_lifetime = self.region_scope_tree.temporary_scope(hir_expr.hir_id.local_id); let expr_scope = region::Scope { id: hir_expr.hir_id.local_id, data: region::ScopeData::Node }; @@ -66,7 +52,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { span: hir_expr.span, kind: ExprKind::Scope { region_scope: expr_scope, - value: self.arena.alloc(expr), + value: self.thir.exprs.push(expr), lint_level: LintLevel::Explicit(hir_expr.hir_id), }, }; @@ -81,22 +67,22 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { span: hir_expr.span, kind: ExprKind::Scope { region_scope, - value: self.arena.alloc(expr), + value: self.thir.exprs.push(expr), lint_level: LintLevel::Inherited, }, }; } // OK, all done! - expr + self.thir.exprs.push(expr) } fn apply_adjustment( &mut self, hir_expr: &'tcx hir::Expr<'tcx>, - mut expr: Expr<'thir, 'tcx>, + mut expr: Expr<'tcx>, adjustment: &Adjustment<'tcx>, - ) -> Expr<'thir, 'tcx> { + ) -> Expr<'tcx> { let Expr { temp_lifetime, mut span, .. } = expr; // Adjust the span from the block, to the last expression of the @@ -109,10 +95,10 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { // x // // ^ error message points at this expression. // } - let mut adjust_span = |expr: &mut Expr<'thir, 'tcx>| { + let mut adjust_span = |expr: &mut Expr<'tcx>| { if let ExprKind::Block { body } = &expr.kind { - if let Some(ref last_expr) = body.expr { - span = last_expr.span; + if let Some(last_expr) = body.expr { + span = self.thir[last_expr].span; expr.span = span; } } @@ -121,13 +107,13 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { let kind = match adjustment.kind { Adjust::Pointer(PointerCast::Unsize) => { adjust_span(&mut expr); - ExprKind::Pointer { cast: PointerCast::Unsize, source: self.arena.alloc(expr) } + ExprKind::Pointer { cast: PointerCast::Unsize, source: self.thir.exprs.push(expr) } } - Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.arena.alloc(expr) }, - Adjust::NeverToAny => ExprKind::NeverToAny { source: self.arena.alloc(expr) }, + Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.thir.exprs.push(expr) }, + Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) }, Adjust::Deref(None) => { adjust_span(&mut expr); - ExprKind::Deref { arg: self.arena.alloc(expr) } + ExprKind::Deref { arg: self.thir.exprs.push(expr) } } Adjust::Deref(Some(deref)) => { // We don't need to do call adjust_span here since @@ -142,30 +128,27 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { span, kind: ExprKind::Borrow { borrow_kind: deref.mutbl.to_borrow_kind(), - arg: self.arena.alloc(expr), + arg: self.thir.exprs.push(expr), }, }; - self.overloaded_place( - hir_expr, - adjustment.target, - Some(call), - self.arena.alloc_from_iter(iter::once(expr)), - deref.span, - ) - } - Adjust::Borrow(AutoBorrow::Ref(_, m)) => { - ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: self.arena.alloc(expr) } + let expr = box [self.thir.exprs.push(expr)]; + + self.overloaded_place(hir_expr, adjustment.target, Some(call), expr, deref.span) } + Adjust::Borrow(AutoBorrow::Ref(_, m)) => ExprKind::Borrow { + borrow_kind: m.to_borrow_kind(), + arg: self.thir.exprs.push(expr), + }, Adjust::Borrow(AutoBorrow::RawPtr(mutability)) => { - ExprKind::AddressOf { mutability, arg: self.arena.alloc(expr) } + ExprKind::AddressOf { mutability, arg: self.thir.exprs.push(expr) } } }; Expr { temp_lifetime, ty: adjustment.target, span, kind } } - fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'thir, 'tcx> { + fn make_mirror_unadjusted(&mut self, expr: &'tcx hir::Expr<'tcx>) -> Expr<'tcx> { let expr_ty = self.typeck_results().expr_ty(expr); let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); @@ -177,7 +160,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { let args = self.mirror_exprs(args); ExprKind::Call { ty: expr.ty, - fun: self.arena.alloc(expr), + fun: self.thir.exprs.push(expr), args, from_hir_call: true, fn_span, @@ -202,13 +185,12 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { span: expr.span, kind: ExprKind::Tuple { fields: self.mirror_exprs(args) }, }; + let tupled_args = self.thir.exprs.push(tupled_args); ExprKind::Call { ty: method.ty, - fun: self.arena.alloc(method), - args: self - .arena - .alloc_from_iter(vec![self.mirror_expr_inner(fun), tupled_args]), + fun: self.thir.exprs.push(method), + args: box [self.mirror_expr(fun), tupled_args], from_hir_call: true, fn_span: expr.span, } @@ -238,10 +220,14 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { }); debug!("make_mirror_unadjusted: (call) user_ty={:?}", user_ty); - let field_refs = - self.arena.alloc_from_iter(args.iter().enumerate().map(|(idx, e)| { - FieldExpr { name: Field::new(idx), expr: self.mirror_expr(e) } - })); + let field_refs = args + .iter() + .enumerate() + .map(|(idx, e)| FieldExpr { + name: Field::new(idx), + expr: self.mirror_expr(e), + }) + .collect(); ExprKind::Adt { adt_def, substs, @@ -278,9 +264,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { hir::ExprKind::AssignOp(op, ref lhs, ref rhs) => { if self.typeck_results().is_method_call(expr) { - let lhs = self.mirror_expr_inner(lhs); - let rhs = self.mirror_expr_inner(rhs); - self.overloaded_operator(expr, self.arena.alloc_from_iter(vec![lhs, rhs])) + let lhs = self.mirror_expr(lhs); + let rhs = self.mirror_expr(rhs); + self.overloaded_operator(expr, box [lhs, rhs]) } else { ExprKind::AssignOp { op: bin_op(op.node), @@ -298,9 +284,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { hir::ExprKind::Binary(op, ref lhs, ref rhs) => { if self.typeck_results().is_method_call(expr) { - let lhs = self.mirror_expr_inner(lhs); - let rhs = self.mirror_expr_inner(rhs); - self.overloaded_operator(expr, self.arena.alloc_from_iter(vec![lhs, rhs])) + let lhs = self.mirror_expr(lhs); + let rhs = self.mirror_expr(rhs); + self.overloaded_operator(expr, box [lhs, rhs]) } else { // FIXME overflow match op.node { @@ -329,15 +315,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { hir::ExprKind::Index(ref lhs, ref index) => { if self.typeck_results().is_method_call(expr) { - let lhs = self.mirror_expr_inner(lhs); - let index = self.mirror_expr_inner(index); - self.overloaded_place( - expr, - expr_ty, - None, - self.arena.alloc_from_iter(vec![lhs, index]), - expr.span, - ) + let lhs = self.mirror_expr(lhs); + let index = self.mirror_expr(index); + self.overloaded_place(expr, expr_ty, None, box [lhs, index], expr.span) } else { ExprKind::Index { lhs: self.mirror_expr(lhs), index: self.mirror_expr(index) } } @@ -345,14 +325,8 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { hir::ExprKind::Unary(hir::UnOp::Deref, ref arg) => { if self.typeck_results().is_method_call(expr) { - let arg = self.mirror_expr_inner(arg); - self.overloaded_place( - expr, - expr_ty, - None, - self.arena.alloc_from_iter(iter::once(arg)), - expr.span, - ) + let arg = self.mirror_expr(arg); + self.overloaded_place(expr, expr_ty, None, box [arg], expr.span) } else { ExprKind::Deref { arg: self.mirror_expr(arg) } } @@ -360,8 +334,8 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { hir::ExprKind::Unary(hir::UnOp::Not, ref arg) => { if self.typeck_results().is_method_call(expr) { - let arg = self.mirror_expr_inner(arg); - self.overloaded_operator(expr, self.arena.alloc_from_iter(iter::once(arg))) + let arg = self.mirror_expr(arg); + self.overloaded_operator(expr, box [arg]) } else { ExprKind::Unary { op: UnOp::Not, arg: self.mirror_expr(arg) } } @@ -369,8 +343,8 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { hir::ExprKind::Unary(hir::UnOp::Neg, ref arg) => { if self.typeck_results().is_method_call(expr) { - let arg = self.mirror_expr_inner(arg); - self.overloaded_operator(expr, self.arena.alloc_from_iter(iter::once(arg))) + let arg = self.mirror_expr(arg); + self.overloaded_operator(expr, box [arg]) } else if let hir::ExprKind::Lit(ref lit) = arg.kind { ExprKind::Literal { literal: self.const_eval_literal(&lit.node, expr_ty, lit.span, true), @@ -396,11 +370,10 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { fields: self.field_refs(fields), base: base.as_ref().map(|base| FruInfo { base: self.mirror_expr(base), - field_types: self.arena.alloc_from_iter( - self.typeck_results().fru_field_types()[expr.hir_id] - .iter() - .cloned(), - ), + field_types: self.typeck_results().fru_field_types()[expr.hir_id] + .iter() + .copied() + .collect(), }), } } @@ -447,12 +420,15 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { } }; - let upvars = self.arena.alloc_from_iter( - self.typeck_results - .closure_min_captures_flattened(def_id) - .zip(substs.upvar_tys()) - .map(|(captured_place, ty)| self.capture_upvar(expr, captured_place, ty)), - ); + let upvars = self + .typeck_results + .closure_min_captures_flattened(def_id) + .zip(substs.upvar_tys()) + .map(|(captured_place, ty)| { + let upvars = self.capture_upvar(expr, captured_place, ty); + self.thir.exprs.push(upvars) + }) + .collect(); // Convert the closure fake reads, if any, from hir `Place` to ExprRef let fake_reads = match self.typeck_results.closure_fake_reads.get(&def_id) { @@ -460,8 +436,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { .iter() .map(|(place, cause, hir_id)| { let expr = self.convert_captured_hir_place(expr, place.clone()); - let expr_ref: &'thir Expr<'thir, 'tcx> = self.arena.alloc(expr); - (expr_ref, *cause, *hir_id) + (self.thir.exprs.push(expr), *cause, *hir_id) }) .collect(), None => Vec::new(), @@ -477,99 +452,105 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { hir::ExprKind::InlineAsm(ref asm) => ExprKind::InlineAsm { template: asm.template, - operands: self.arena.alloc_from_iter(asm.operands.iter().map(|(op, _op_sp)| { - match *op { - hir::InlineAsmOperand::In { reg, ref expr } => { - InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) } - } - hir::InlineAsmOperand::Out { reg, late, ref expr } => { - InlineAsmOperand::Out { + operands: asm + .operands + .iter() + .map(|(op, _op_sp)| { + match *op { + hir::InlineAsmOperand::In { reg, ref expr } => { + InlineAsmOperand::In { reg, expr: self.mirror_expr(expr) } + } + hir::InlineAsmOperand::Out { reg, late, ref expr } => { + InlineAsmOperand::Out { + reg, + late, + expr: expr.as_ref().map(|expr| self.mirror_expr(expr)), + } + } + hir::InlineAsmOperand::InOut { reg, late, ref expr } => { + InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) } + } + hir::InlineAsmOperand::SplitInOut { reg, late, - expr: expr.as_ref().map(|expr| self.mirror_expr(expr)), - } - } - hir::InlineAsmOperand::InOut { reg, late, ref expr } => { - InlineAsmOperand::InOut { reg, late, expr: self.mirror_expr(expr) } - } - hir::InlineAsmOperand::SplitInOut { - reg, - late, - ref in_expr, - ref out_expr, - } => InlineAsmOperand::SplitInOut { - reg, - late, - in_expr: self.mirror_expr(in_expr), - out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)), - }, - hir::InlineAsmOperand::Const { ref anon_const } => { - let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id); - let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id); - let span = self.tcx.hir().span(anon_const.hir_id); + ref in_expr, + ref out_expr, + } => InlineAsmOperand::SplitInOut { + reg, + late, + in_expr: self.mirror_expr(in_expr), + out_expr: out_expr.as_ref().map(|expr| self.mirror_expr(expr)), + }, + hir::InlineAsmOperand::Const { ref anon_const } => { + let anon_const_def_id = + self.tcx.hir().local_def_id(anon_const.hir_id); + let value = ty::Const::from_anon_const(self.tcx, anon_const_def_id); + let span = self.tcx.hir().span(anon_const.hir_id); - InlineAsmOperand::Const { value, span } - } - hir::InlineAsmOperand::Sym { ref expr } => { - let qpath = match expr.kind { - hir::ExprKind::Path(ref qpath) => qpath, - _ => span_bug!( - expr.span, - "asm `sym` operand should be a path, found {:?}", - expr.kind - ), - }; - let temp_lifetime = - self.region_scope_tree.temporary_scope(expr.hir_id.local_id); - let res = self.typeck_results().qpath_res(qpath, expr.hir_id); - let ty; - match res { - Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) => { - ty = self.typeck_results().node_type(expr.hir_id); - let user_ty = self.user_substs_applied_to_res(expr.hir_id, res); - InlineAsmOperand::SymFn { - expr: self.arena.alloc(Expr { - ty, - temp_lifetime, - span: expr.span, - kind: ExprKind::Literal { - literal: ty::Const::zero_sized(self.tcx, ty), - user_ty, - const_id: None, - }, - }), + InlineAsmOperand::Const { value, span } + } + hir::InlineAsmOperand::Sym { ref expr } => { + let qpath = match expr.kind { + hir::ExprKind::Path(ref qpath) => qpath, + _ => span_bug!( + expr.span, + "asm `sym` operand should be a path, found {:?}", + expr.kind + ), + }; + let temp_lifetime = + self.region_scope_tree.temporary_scope(expr.hir_id.local_id); + let res = self.typeck_results().qpath_res(qpath, expr.hir_id); + let ty; + match res { + Res::Def(DefKind::Fn, _) | Res::Def(DefKind::AssocFn, _) => { + ty = self.typeck_results().node_type(expr.hir_id); + let user_ty = + self.user_substs_applied_to_res(expr.hir_id, res); + InlineAsmOperand::SymFn { + expr: self.thir.exprs.push(Expr { + ty, + temp_lifetime, + span: expr.span, + kind: ExprKind::Literal { + literal: ty::Const::zero_sized(self.tcx, ty), + user_ty, + const_id: None, + }, + }), + } } - } - Res::Def(DefKind::Static, def_id) => { - InlineAsmOperand::SymStatic { def_id } - } + Res::Def(DefKind::Static, def_id) => { + InlineAsmOperand::SymStatic { def_id } + } - _ => { - self.tcx.sess.span_err( - expr.span, - "asm `sym` operand must point to a fn or static", - ); - - // Not a real fn, but we're not reaching codegen anyways... - ty = self.tcx.ty_error(); - InlineAsmOperand::SymFn { - expr: self.arena.alloc(Expr { - ty, - temp_lifetime, - span: expr.span, - kind: ExprKind::Literal { - literal: ty::Const::zero_sized(self.tcx, ty), - user_ty: None, - const_id: None, - }, - }), + _ => { + self.tcx.sess.span_err( + expr.span, + "asm `sym` operand must point to a fn or static", + ); + + // Not a real fn, but we're not reaching codegen anyways... + ty = self.tcx.ty_error(); + InlineAsmOperand::SymFn { + expr: self.thir.exprs.push(Expr { + ty, + temp_lifetime, + span: expr.span, + kind: ExprKind::Literal { + literal: ty::Const::zero_sized(self.tcx, ty), + user_ty: None, + const_id: None, + }, + }), + } } } } } - } - })), + }) + .collect(), options: asm.options, line_spans: asm.line_spans, }, @@ -616,13 +597,13 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { }, hir::ExprKind::Match(ref discr, ref arms, _) => ExprKind::Match { scrutinee: self.mirror_expr(discr), - arms: self.arena.alloc_from_iter(arms.iter().map(|a| self.convert_arm(a))), + arms: arms.iter().map(|a| self.convert_arm(a)).collect(), }, hir::ExprKind::Loop(ref body, ..) => { let block_ty = self.typeck_results().node_type(body.hir_id); let temp_lifetime = self.region_scope_tree.temporary_scope(body.hir_id.local_id); let block = self.mirror_block(body); - let body = self.arena.alloc(Expr { + let body = self.thir.exprs.push(Expr { ty: block_ty, temp_lifetime, span: block.span, @@ -692,35 +673,34 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { }; let source = if let Some((did, offset, var_ty)) = var { - let mk_const = |literal| { - self.arena.alloc(Expr { - temp_lifetime, - ty: var_ty, - span: expr.span, - kind: ExprKind::Literal { literal, user_ty: None, const_id: None }, - }) + let mk_const = |literal| Expr { + temp_lifetime, + ty: var_ty, + span: expr.span, + kind: ExprKind::Literal { literal, user_ty: None, const_id: None }, }; - let offset = mk_const(ty::Const::from_bits( + let offset = self.thir.exprs.push(mk_const(ty::Const::from_bits( self.tcx, offset as u128, self.param_env.and(var_ty), - )); + ))); match did { Some(did) => { // in case we are offsetting from a computed discriminant // and not the beginning of discriminants (which is always `0`) let substs = InternalSubsts::identity_for_item(self.tcx(), did); - let lhs = mk_const(self.tcx().mk_const(ty::Const { + let lhs = ty::Const { val: ty::ConstKind::Unevaluated(ty::Unevaluated { def: ty::WithOptConstParam::unknown(did), substs, promoted: None, }), ty: var_ty, - })); + }; + let lhs = self.thir.exprs.push(mk_const(self.tcx().mk_const(lhs))); let bin = ExprKind::Binary { op: BinOp::Add, lhs: lhs, rhs: offset }; - self.arena.alloc(Expr { + self.thir.exprs.push(Expr { temp_lifetime, ty: var_ty, span: expr.span, @@ -739,7 +719,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { if let Some(user_ty) = user_ty { // NOTE: Creating a new Expr and wrapping a Cast inside of it may be // inefficient, revisit this when performance becomes an issue. - let cast_expr = self.arena.alloc(Expr { + let cast_expr = self.thir.exprs.push(Expr { temp_lifetime, ty: expr_ty, span: expr.span, @@ -819,7 +799,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { expr: &hir::Expr<'_>, span: Span, overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, - ) -> Expr<'thir, 'tcx> { + ) -> Expr<'tcx> { let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); let (def_id, substs, user_ty) = match overloaded_callee { Some((def_id, substs)) => (def_id, substs, None), @@ -846,8 +826,8 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { } } - fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> Arm<'thir, 'tcx> { - Arm { + fn convert_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) -> ArmId { + let arm = Arm { pattern: self.pattern_from_hir(&arm.pat), guard: arm.guard.as_ref().map(|g| match g { hir::Guard::If(ref e) => Guard::If(self.mirror_expr(e)), @@ -859,14 +839,11 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { lint_level: LintLevel::Explicit(arm.hir_id), scope: region::Scope { id: arm.hir_id.local_id, data: region::ScopeData::Node }, span: arm.span, - } + }; + self.thir.arms.push(arm) } - fn convert_path_expr( - &mut self, - expr: &'tcx hir::Expr<'tcx>, - res: Res, - ) -> ExprKind<'thir, 'tcx> { + fn convert_path_expr(&mut self, expr: &'tcx hir::Expr<'tcx>, res: Res) -> ExprKind<'tcx> { let substs = self.typeck_results().node_substs(expr.hir_id); match res { // A regular function, constructor function or a constant. @@ -934,7 +911,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { variant_index: adt_def.variant_index_with_ctor_id(def_id), substs, user_ty: user_provided_type, - fields: self.arena.alloc_from_iter(iter::empty()), + fields: box [], base: None, }, _ => bug!("unexpected ty: {:?}", ty), @@ -956,7 +933,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { } }; ExprKind::Deref { - arg: self.arena.alloc(Expr { ty, temp_lifetime, span: expr.span, kind }), + arg: self.thir.exprs.push(Expr { ty, temp_lifetime, span: expr.span, kind }), } } @@ -966,7 +943,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { } } - fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'thir, 'tcx> { + fn convert_var(&mut self, var_hir_id: hir::HirId) -> ExprKind<'tcx> { // We want upvars here not captures. // Captures will be handled in MIR. let is_upvar = self @@ -989,10 +966,17 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { fn overloaded_operator( &mut self, expr: &'tcx hir::Expr<'tcx>, - args: &'thir [Expr<'thir, 'tcx>], - ) -> ExprKind<'thir, 'tcx> { - let fun = self.arena.alloc(self.method_callee(expr, expr.span, None)); - ExprKind::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: expr.span } + args: Box<[ExprId]>, + ) -> ExprKind<'tcx> { + let fun = self.method_callee(expr, expr.span, None); + let fun = self.thir.exprs.push(fun); + ExprKind::Call { + ty: self.thir[fun].ty, + fun, + args, + from_hir_call: false, + fn_span: expr.span, + } } fn overloaded_place( @@ -1000,9 +984,9 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { expr: &'tcx hir::Expr<'tcx>, place_ty: Ty<'tcx>, overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, - args: &'thir [Expr<'thir, 'tcx>], + args: Box<[ExprId]>, span: Span, - ) -> ExprKind<'thir, 'tcx> { + ) -> ExprKind<'tcx> { // For an overloaded *x or x[y] expression of type T, the method // call returns an &T and we must add the deref so that the types // line up (this is because `*x` and `x[y]` represent places): @@ -1010,7 +994,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { // Reconstruct the output assuming it's a reference with the // same region and mutability as the receiver. This holds for // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. - let (region, mutbl) = match *args[0].ty.kind() { + let (region, mutbl) = match *self.thir[args[0]].ty.kind() { ty::Ref(region, _, mutbl) => (region, mutbl), _ => span_bug!(span, "overloaded_place: receiver is not a reference"), }; @@ -1019,12 +1003,14 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type let temp_lifetime = self.region_scope_tree.temporary_scope(expr.hir_id.local_id); - let fun = self.arena.alloc(self.method_callee(expr, span, overloaded_callee)); - let ref_expr = self.arena.alloc(Expr { + let fun = self.method_callee(expr, span, overloaded_callee); + let fun = self.thir.exprs.push(fun); + let fun_ty = self.thir[fun].ty; + let ref_expr = self.thir.exprs.push(Expr { temp_lifetime, ty: ref_ty, span, - kind: ExprKind::Call { ty: fun.ty, fun, args, from_hir_call: false, fn_span: span }, + kind: ExprKind::Call { ty: fun_ty, fun, args, from_hir_call: false, fn_span: span }, }); // construct and return a deref wrapper `*foo()` @@ -1035,7 +1021,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { &mut self, closure_expr: &'tcx hir::Expr<'tcx>, place: HirPlace<'tcx>, - ) -> Expr<'thir, 'tcx> { + ) -> Expr<'tcx> { let temp_lifetime = self.region_scope_tree.temporary_scope(closure_expr.hir_id.local_id); let var_ty = place.base_ty; @@ -1059,13 +1045,13 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { for proj in place.projections.iter() { let kind = match proj.kind { HirProjectionKind::Deref => { - ExprKind::Deref { arg: self.arena.alloc(captured_place_expr) } + ExprKind::Deref { arg: self.thir.exprs.push(captured_place_expr) } } HirProjectionKind::Field(field, ..) => { // Variant index will always be 0, because for multi-variant // enums, we capture the enum entirely. ExprKind::Field { - lhs: self.arena.alloc(captured_place_expr), + lhs: self.thir.exprs.push(captured_place_expr), name: Field::new(field as usize), } } @@ -1087,7 +1073,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { closure_expr: &'tcx hir::Expr<'tcx>, captured_place: &'tcx ty::CapturedPlace<'tcx>, upvar_ty: Ty<'tcx>, - ) -> Expr<'thir, 'tcx> { + ) -> Expr<'tcx> { let upvar_capture = captured_place.info.capture_kind; let captured_place_expr = self.convert_captured_hir_place(closure_expr, captured_place.place.clone()); @@ -1107,7 +1093,7 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { span: closure_expr.span, kind: ExprKind::Borrow { borrow_kind, - arg: self.arena.alloc(captured_place_expr), + arg: self.thir.exprs.push(captured_place_expr), }, } } @@ -1115,14 +1101,14 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { } /// Converts a list of named fields (i.e., for struct-like struct/enum ADTs) into FieldExpr. - fn field_refs( - &mut self, - fields: &'tcx [hir::ExprField<'tcx>], - ) -> &'thir [FieldExpr<'thir, 'tcx>] { - self.arena.alloc_from_iter(fields.iter().map(|field| FieldExpr { - name: Field::new(self.tcx.field_index(field.hir_id, self.typeck_results)), - expr: self.mirror_expr(field.expr), - })) + fn field_refs(&mut self, fields: &'tcx [hir::ExprField<'tcx>]) -> Box<[FieldExpr]> { + fields + .iter() + .map(|field| FieldExpr { + name: Field::new(self.tcx.field_index(field.hir_id, self.typeck_results)), + expr: self.mirror_expr(field.expr), + }) + .collect() } } diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index c0433604f8c..49ba71e3520 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -2,30 +2,37 @@ //! structures into the THIR. The `builder` is generally ignorant of the tcx, //! etc., and instead goes through the `Cx` for most of its work. -use crate::thir::arena::Arena; +use crate::thir::pattern::pat_from_hir; use crate::thir::util::UserAnnotatedTyHelpers; -use crate::thir::*; use rustc_ast as ast; +use rustc_data_structures::steal::Steal; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::Node; use rustc_middle::middle::region; use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; +use rustc_middle::thir::*; use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::Span; -pub fn build_thir<'thir, 'tcx>( +crate fn thir_body<'tcx>( tcx: TyCtxt<'tcx>, owner_def: ty::WithOptConstParam<LocalDefId>, - arena: &'thir Arena<'thir, 'tcx>, - expr: &'tcx hir::Expr<'tcx>, -) -> &'thir Expr<'thir, 'tcx> { - Cx::new(tcx, owner_def, &arena).mirror_expr(expr) +) -> (&'tcx Steal<Thir<'tcx>>, ExprId) { + let hir = tcx.hir(); + let body = hir.body(hir.body_owned_by(hir.local_def_id_to_hir_id(owner_def.did))); + let mut cx = Cx::new(tcx, owner_def); + if cx.typeck_results.tainted_by_errors.is_some() { + return (tcx.alloc_steal_thir(Thir::new()), ExprId::from_u32(0)); + } + let expr = cx.mirror_expr(&body.value); + (tcx.alloc_steal_thir(cx.thir), expr) } -struct Cx<'thir, 'tcx> { +struct Cx<'tcx> { tcx: TyCtxt<'tcx>, - arena: &'thir Arena<'thir, 'tcx>, + thir: Thir<'tcx>, crate param_env: ty::ParamEnv<'tcx>, @@ -36,16 +43,12 @@ struct Cx<'thir, 'tcx> { body_owner: DefId, } -impl<'thir, 'tcx> Cx<'thir, 'tcx> { - fn new( - tcx: TyCtxt<'tcx>, - def: ty::WithOptConstParam<LocalDefId>, - arena: &'thir Arena<'thir, 'tcx>, - ) -> Cx<'thir, 'tcx> { +impl<'tcx> Cx<'tcx> { + fn new(tcx: TyCtxt<'tcx>, def: ty::WithOptConstParam<LocalDefId>) -> Cx<'tcx> { let typeck_results = tcx.typeck_opt_const_arg(def); Cx { tcx, - arena, + thir: Thir::new(), param_env: tcx.param_env(def.did), region_scope_tree: tcx.region_scope_tree(def.did), typeck_results, @@ -83,11 +86,11 @@ impl<'thir, 'tcx> Cx<'thir, 'tcx> { Node::Pat(p) | Node::Binding(p) => p, node => bug!("pattern became {:?}", node), }; - Pat::from_hir(self.tcx, self.param_env, self.typeck_results(), p) + pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p) } } -impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'_, 'tcx> { +impl<'tcx> UserAnnotatedTyHelpers<'tcx> for Cx<'tcx> { fn tcx(&self) -> TyCtxt<'tcx> { self.tcx } diff --git a/compiler/rustc_mir_build/src/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs index 9bcb000920c..e5123d8ef0c 100644 --- a/compiler/rustc_mir_build/src/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -4,384 +4,11 @@ //! unit-tested and separated from the Rust source and compiler data //! structures. -use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_middle::infer::canonical::Canonical; -use rustc_middle::middle::region; -use rustc_middle::mir::{BinOp, BorrowKind, FakeReadCause, Field, UnOp}; -use rustc_middle::ty::adjustment::PointerCast; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{AdtDef, Const, Ty, UpvarSubsts, UserType}; -use rustc_span::Span; -use rustc_target::abi::VariantIdx; -use rustc_target::asm::InlineAsmRegOrRegClass; - crate mod constant; crate mod cx; -pub use cx::build_thir; crate mod pattern; -pub use self::pattern::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj}; - -mod arena; -pub use arena::Arena; mod util; pub mod visit; - -#[derive(Copy, Clone, Debug)] -pub enum LintLevel { - Inherited, - Explicit(hir::HirId), -} - -#[derive(Debug)] -pub struct Block<'thir, 'tcx> { - pub targeted_by_break: bool, - pub region_scope: region::Scope, - pub opt_destruction_scope: Option<region::Scope>, - pub span: Span, - pub stmts: &'thir [Stmt<'thir, 'tcx>], - pub expr: Option<&'thir Expr<'thir, 'tcx>>, - pub safety_mode: BlockSafety, -} - -#[derive(Copy, Clone, Debug)] -pub enum BlockSafety { - Safe, - ExplicitUnsafe(hir::HirId), - PushUnsafe, - PopUnsafe, -} - -#[derive(Debug)] -pub struct Stmt<'thir, 'tcx> { - pub kind: StmtKind<'thir, 'tcx>, - pub opt_destruction_scope: Option<region::Scope>, -} - -#[derive(Debug)] -pub enum StmtKind<'thir, 'tcx> { - Expr { - /// scope for this statement; may be used as lifetime of temporaries - scope: region::Scope, - - /// expression being evaluated in this statement - expr: &'thir Expr<'thir, 'tcx>, - }, - - Let { - /// scope for variables bound in this let; covers this and - /// remaining statements in block - remainder_scope: region::Scope, - - /// scope for the initialization itself; might be used as - /// lifetime of temporaries - init_scope: region::Scope, - - /// `let <PAT> = ...` - /// - /// if a type is included, it is added as an ascription pattern - pattern: Pat<'tcx>, - - /// let pat: ty = <INIT> ... - initializer: Option<&'thir Expr<'thir, 'tcx>>, - - /// the lint level for this let-statement - lint_level: LintLevel, - }, -} - -// `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -rustc_data_structures::static_assert_size!(Expr<'_, '_>, 144); - -/// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`) -/// into instances of this `Expr` enum. This lowering can be done -/// basically as lazily or as eagerly as desired: every recursive -/// reference to an expression in this enum is an `&'thir Expr<'thir, 'tcx>`, which -/// may in turn be another instance of this enum (boxed), or else an -/// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very -/// short-lived. They are created by `Thir::to_expr`, analyzed and -/// converted into MIR, and then discarded. -/// -/// If you compare `Expr` to the full compiler AST, you will see it is -/// a good bit simpler. In fact, a number of the more straight-forward -/// MIR simplifications are already done in the impl of `Thir`. For -/// example, method calls and overloaded operators are absent: they are -/// expected to be converted into `Expr::Call` instances. -#[derive(Debug)] -pub struct Expr<'thir, 'tcx> { - /// type of this expression - pub ty: Ty<'tcx>, - - /// lifetime of this expression if it should be spilled into a - /// temporary; should be None only if in a constant context - pub temp_lifetime: Option<region::Scope>, - - /// span of the expression in the source - pub span: Span, - - /// kind of expression - pub kind: ExprKind<'thir, 'tcx>, -} - -#[derive(Debug)] -pub enum ExprKind<'thir, 'tcx> { - Scope { - region_scope: region::Scope, - lint_level: LintLevel, - value: &'thir Expr<'thir, 'tcx>, - }, - Box { - value: &'thir Expr<'thir, 'tcx>, - }, - If { - cond: &'thir Expr<'thir, 'tcx>, - then: &'thir Expr<'thir, 'tcx>, - else_opt: Option<&'thir Expr<'thir, 'tcx>>, - }, - Call { - ty: Ty<'tcx>, - fun: &'thir Expr<'thir, 'tcx>, - args: &'thir [Expr<'thir, 'tcx>], - /// Whether this is from a call in HIR, rather than from an overloaded - /// operator. `true` for overloaded function call. - from_hir_call: bool, - /// This `Span` is the span of the function, without the dot and receiver - /// (e.g. `foo(a, b)` in `x.foo(a, b)` - fn_span: Span, - }, - Deref { - arg: &'thir Expr<'thir, 'tcx>, - }, // NOT overloaded! - Binary { - op: BinOp, - lhs: &'thir Expr<'thir, 'tcx>, - rhs: &'thir Expr<'thir, 'tcx>, - }, // NOT overloaded! - LogicalOp { - op: LogicalOp, - lhs: &'thir Expr<'thir, 'tcx>, - rhs: &'thir Expr<'thir, 'tcx>, - }, // NOT overloaded! - // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands. - Unary { - op: UnOp, - arg: &'thir Expr<'thir, 'tcx>, - }, // NOT overloaded! - Cast { - source: &'thir Expr<'thir, 'tcx>, - }, - Use { - source: &'thir Expr<'thir, 'tcx>, - }, // Use a lexpr to get a vexpr. - NeverToAny { - source: &'thir Expr<'thir, 'tcx>, - }, - Pointer { - cast: PointerCast, - source: &'thir Expr<'thir, 'tcx>, - }, - Loop { - body: &'thir Expr<'thir, 'tcx>, - }, - Match { - scrutinee: &'thir Expr<'thir, 'tcx>, - arms: &'thir [Arm<'thir, 'tcx>], - }, - Block { - body: Block<'thir, 'tcx>, - }, - Assign { - lhs: &'thir Expr<'thir, 'tcx>, - rhs: &'thir Expr<'thir, 'tcx>, - }, - AssignOp { - op: BinOp, - lhs: &'thir Expr<'thir, 'tcx>, - rhs: &'thir Expr<'thir, 'tcx>, - }, - Field { - lhs: &'thir Expr<'thir, 'tcx>, - name: Field, - }, - Index { - lhs: &'thir Expr<'thir, 'tcx>, - index: &'thir Expr<'thir, 'tcx>, - }, - VarRef { - id: hir::HirId, - }, - /// Used to represent upvars mentioned in a closure/generator - UpvarRef { - /// DefId of the closure/generator - closure_def_id: DefId, - - /// HirId of the root variable - var_hir_id: hir::HirId, - }, - Borrow { - borrow_kind: BorrowKind, - arg: &'thir Expr<'thir, 'tcx>, - }, - /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`. - AddressOf { - mutability: hir::Mutability, - arg: &'thir Expr<'thir, 'tcx>, - }, - Break { - label: region::Scope, - value: Option<&'thir Expr<'thir, 'tcx>>, - }, - Continue { - label: region::Scope, - }, - Return { - value: Option<&'thir Expr<'thir, 'tcx>>, - }, - ConstBlock { - value: &'tcx Const<'tcx>, - }, - Repeat { - value: &'thir Expr<'thir, 'tcx>, - count: &'tcx Const<'tcx>, - }, - Array { - fields: &'thir [Expr<'thir, 'tcx>], - }, - Tuple { - fields: &'thir [Expr<'thir, 'tcx>], - }, - Adt { - adt_def: &'tcx AdtDef, - variant_index: VariantIdx, - substs: SubstsRef<'tcx>, - - /// Optional user-given substs: for something like `let x = - /// Bar::<T> { ... }`. - user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, - - fields: &'thir [FieldExpr<'thir, 'tcx>], - base: Option<FruInfo<'thir, 'tcx>>, - }, - PlaceTypeAscription { - source: &'thir Expr<'thir, 'tcx>, - /// Type that the user gave to this expression - user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, - }, - ValueTypeAscription { - source: &'thir Expr<'thir, 'tcx>, - /// Type that the user gave to this expression - user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, - }, - Closure { - closure_id: DefId, - substs: UpvarSubsts<'tcx>, - upvars: &'thir [Expr<'thir, 'tcx>], - movability: Option<hir::Movability>, - fake_reads: Vec<(&'thir Expr<'thir, 'tcx>, FakeReadCause, hir::HirId)>, - }, - Literal { - literal: &'tcx Const<'tcx>, - user_ty: Option<Canonical<'tcx, UserType<'tcx>>>, - /// The `DefId` of the `const` item this literal - /// was produced from, if this is not a user-written - /// literal value. - const_id: Option<DefId>, - }, - /// A literal containing the address of a `static`. - /// - /// This is only distinguished from `Literal` so that we can register some - /// info for diagnostics. - StaticRef { - literal: &'tcx Const<'tcx>, - def_id: DefId, - }, - InlineAsm { - template: &'tcx [InlineAsmTemplatePiece], - operands: &'thir [InlineAsmOperand<'thir, 'tcx>], - options: InlineAsmOptions, - line_spans: &'tcx [Span], - }, - /// An expression taking a reference to a thread local. - ThreadLocalRef(DefId), - LlvmInlineAsm { - asm: &'tcx hir::LlvmInlineAsmInner, - outputs: &'thir [Expr<'thir, 'tcx>], - inputs: &'thir [Expr<'thir, 'tcx>], - }, - Yield { - value: &'thir Expr<'thir, 'tcx>, - }, -} - -#[derive(Debug)] -pub struct FieldExpr<'thir, 'tcx> { - pub name: Field, - pub expr: &'thir Expr<'thir, 'tcx>, -} - -#[derive(Debug)] -pub struct FruInfo<'thir, 'tcx> { - pub base: &'thir Expr<'thir, 'tcx>, - pub field_types: &'thir [Ty<'tcx>], -} - -#[derive(Debug)] -pub struct Arm<'thir, 'tcx> { - pub pattern: Pat<'tcx>, - pub guard: Option<Guard<'thir, 'tcx>>, - pub body: &'thir Expr<'thir, 'tcx>, - pub lint_level: LintLevel, - pub scope: region::Scope, - pub span: Span, -} - -#[derive(Debug)] -pub enum Guard<'thir, 'tcx> { - If(&'thir Expr<'thir, 'tcx>), - IfLet(Pat<'tcx>, &'thir Expr<'thir, 'tcx>), -} - -#[derive(Copy, Clone, Debug)] -pub enum LogicalOp { - And, - Or, -} - -#[derive(Debug)] -pub enum InlineAsmOperand<'thir, 'tcx> { - In { - reg: InlineAsmRegOrRegClass, - expr: &'thir Expr<'thir, 'tcx>, - }, - Out { - reg: InlineAsmRegOrRegClass, - late: bool, - expr: Option<&'thir Expr<'thir, 'tcx>>, - }, - InOut { - reg: InlineAsmRegOrRegClass, - late: bool, - expr: &'thir Expr<'thir, 'tcx>, - }, - SplitInOut { - reg: InlineAsmRegOrRegClass, - late: bool, - in_expr: &'thir Expr<'thir, 'tcx>, - out_expr: Option<&'thir Expr<'thir, 'tcx>>, - }, - Const { - value: &'tcx Const<'tcx>, - span: Span, - }, - SymFn { - expr: &'thir Expr<'thir, 'tcx>, - }, - SymStatic { - def_id: DefId, - }, -} diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index e4419070cbd..389a7595315 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -1,8 +1,8 @@ use super::usefulness::{ - compute_match_usefulness, expand_pattern, MatchArm, MatchCheckCtxt, Reachability, + compute_match_usefulness, expand_pattern, is_wildcard, MatchArm, MatchCheckCtxt, Reachability, UsefulnessReport, }; -use super::{PatCtxt, PatKind, PatternError}; +use super::{PatCtxt, PatternError}; use rustc_arena::TypedArena; use rustc_ast::Mutability; @@ -12,6 +12,7 @@ use rustc_hir::def::*; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{HirId, Pat}; +use rustc_middle::thir::PatKind; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::lint::builtin::BINDINGS_WITH_VARIANT_NAME; use rustc_session::lint::builtin::{IRREFUTABLE_LET_PATTERNS, UNREACHABLE_PATTERNS}; @@ -344,7 +345,7 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa /// Checks for common cases of "catchall" patterns that may not be intended as such. fn pat_is_catchall(pat: &super::Pat<'_>) -> bool { - use super::PatKind::*; + use PatKind::*; match &*pat.kind { Binding { subpattern: None, .. } => true, Binding { subpattern: Some(s), .. } | Deref { subpattern: s } => pat_is_catchall(s), @@ -514,7 +515,7 @@ fn non_exhaustive_match<'p, 'tcx>( if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize) && !is_empty_match && witnesses.len() == 1 - && witnesses[0].is_wildcard() + && is_wildcard(&witnesses[0]) { err.note(&format!( "`{}` does not have a fixed maximum value, \ 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 c0624c805a6..369fff00456 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 @@ -2,6 +2,7 @@ use rustc_hir as hir; use rustc_index::vec::Idx; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::Field; +use rustc_middle::thir::{FieldPat, Pat, PatKind}; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; use rustc_session::lint; @@ -12,7 +13,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; use std::cell::Cell; -use super::{FieldPat, Pat, PatCtxt, PatKind}; +use super::PatCtxt; impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// Converts an evaluated constant to a pattern (if possible). diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index db0f487645f..4b5b648c504 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -46,8 +46,7 @@ use self::Constructor::*; use self::SliceKind::*; use super::compare_const_vals; -use super::usefulness::{MatchCheckCtxt, PatCtxt}; -use super::{FieldPat, Pat, PatKind, PatRange}; +use super::usefulness::{is_wildcard, MatchCheckCtxt, PatCtxt}; use rustc_data_structures::captures::Captures; use rustc_index::vec::Idx; @@ -55,6 +54,7 @@ use rustc_index::vec::Idx; use rustc_hir::{HirId, RangeEnd}; use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::Field; +use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange}; use rustc_middle::ty::layout::IntegerExt; use rustc_middle::ty::{self, Const, Ty, TyCtxt}; use rustc_session::lint; @@ -1245,13 +1245,13 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { // of reporting `[x, _, .., _, y]`, we prefer to report `[x, .., y]`. // This is incorrect if the size is not known, since `[_, ..]` captures // arrays of lengths `>= 1` whereas `[..]` captures any length. - while !prefix.is_empty() && prefix.last().unwrap().is_wildcard() { + while !prefix.is_empty() && is_wildcard(prefix.last().unwrap()) { prefix.pop(); } } let suffix: Vec<_> = if slice.array_len.is_some() { // Same as above. - subpatterns.skip_while(Pat::is_wildcard).collect() + subpatterns.skip_while(is_wildcard).collect() } else { subpatterns.collect() }; diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 9ac79a37ac6..3225d302cb3 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -11,7 +11,7 @@ use crate::thir::util::UserAnnotatedTyHelpers; use rustc_errors::struct_span_err; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; +use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::RangeEnd; use rustc_index::vec::Idx; @@ -19,16 +19,12 @@ use rustc_middle::mir::interpret::{get_slice_bytes, ConstValue}; use rustc_middle::mir::interpret::{ErrorHandled, LitToConstError, LitToConstInput}; use rustc_middle::mir::UserTypeProjection; use rustc_middle::mir::{BorrowKind, Field, Mutability}; +use rustc_middle::thir::{Ascription, BindingMode, FieldPat, Pat, PatKind, PatRange, PatTyProj}; use rustc_middle::ty::subst::{GenericArg, SubstsRef}; use rustc_middle::ty::{self, AdtDef, DefIdTree, Region, Ty, TyCtxt, UserType}; -use rustc_middle::ty::{ - CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, -}; -use rustc_span::{Span, Symbol, DUMMY_SP}; -use rustc_target::abi::VariantIdx; +use rustc_span::{Span, Symbol}; use std::cmp::Ordering; -use std::fmt; #[derive(Clone, Debug)] crate enum PatternError { @@ -39,317 +35,6 @@ crate enum PatternError { NonConstPath(Span), } -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum BindingMode { - ByValue, - ByRef(BorrowKind), -} - -#[derive(Clone, Debug, PartialEq)] -pub struct FieldPat<'tcx> { - pub field: Field, - pub pattern: Pat<'tcx>, -} - -#[derive(Clone, Debug, PartialEq)] -pub struct Pat<'tcx> { - pub ty: Ty<'tcx>, - pub span: Span, - pub kind: Box<PatKind<'tcx>>, -} - -impl<'tcx> Pat<'tcx> { - pub(crate) fn wildcard_from_ty(ty: Ty<'tcx>) -> Self { - Pat { ty, span: DUMMY_SP, kind: Box::new(PatKind::Wild) } - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct PatTyProj<'tcx> { - pub user_ty: CanonicalUserType<'tcx>, -} - -impl<'tcx> PatTyProj<'tcx> { - pub(crate) fn from_user_type(user_annotation: CanonicalUserType<'tcx>) -> Self { - Self { user_ty: user_annotation } - } - - pub(crate) fn user_ty( - self, - annotations: &mut CanonicalUserTypeAnnotations<'tcx>, - inferred_ty: Ty<'tcx>, - span: Span, - ) -> UserTypeProjection { - UserTypeProjection { - base: annotations.push(CanonicalUserTypeAnnotation { - span, - user_ty: self.user_ty, - inferred_ty, - }), - projs: Vec::new(), - } - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct Ascription<'tcx> { - pub user_ty: PatTyProj<'tcx>, - /// Variance to use when relating the type `user_ty` to the **type of the value being - /// matched**. Typically, this is `Variance::Covariant`, since the value being matched must - /// have a type that is some subtype of the ascribed type. - /// - /// Note that this variance does not apply for any bindings within subpatterns. The type - /// assigned to those bindings must be exactly equal to the `user_ty` given here. - /// - /// The only place where this field is not `Covariant` is when matching constants, where - /// we currently use `Contravariant` -- this is because the constant type just needs to - /// be "comparable" to the type of the input value. So, for example: - /// - /// ```text - /// match x { "foo" => .. } - /// ``` - /// - /// requires that `&'static str <: T_x`, where `T_x` is the type of `x`. Really, we should - /// probably be checking for a `PartialEq` impl instead, but this preserves the behavior - /// of the old type-check for now. See #57280 for details. - pub variance: ty::Variance, - pub user_ty_span: Span, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum PatKind<'tcx> { - Wild, - - AscribeUserType { - ascription: Ascription<'tcx>, - subpattern: Pat<'tcx>, - }, - - /// `x`, `ref x`, `x @ P`, etc. - Binding { - mutability: Mutability, - name: Symbol, - mode: BindingMode, - var: hir::HirId, - ty: Ty<'tcx>, - subpattern: Option<Pat<'tcx>>, - /// Is this the leftmost occurrence of the binding, i.e., is `var` the - /// `HirId` of this pattern? - is_primary: bool, - }, - - /// `Foo(...)` or `Foo{...}` or `Foo`, where `Foo` is a variant name from an ADT with - /// multiple variants. - Variant { - adt_def: &'tcx AdtDef, - substs: SubstsRef<'tcx>, - variant_index: VariantIdx, - subpatterns: Vec<FieldPat<'tcx>>, - }, - - /// `(...)`, `Foo(...)`, `Foo{...}`, or `Foo`, where `Foo` is a variant name from an ADT with - /// a single variant. - Leaf { - subpatterns: Vec<FieldPat<'tcx>>, - }, - - /// `box P`, `&P`, `&mut P`, etc. - Deref { - subpattern: Pat<'tcx>, - }, - - /// One of the following: - /// * `&str`, which will be handled as a string pattern and thus exhaustiveness - /// checking will detect if you use the same string twice in different patterns. - /// * integer, bool, char or float, which will be handled by exhaustivenes to cover exactly - /// its own value, similar to `&str`, but these values are much simpler. - /// * Opaque constants, that must not be matched structurally. So anything that does not derive - /// `PartialEq` and `Eq`. - Constant { - value: &'tcx ty::Const<'tcx>, - }, - - Range(PatRange<'tcx>), - - /// Matches against a slice, checking the length and extracting elements. - /// irrefutable when there is a slice pattern and both `prefix` and `suffix` are empty. - /// e.g., `&[ref xs @ ..]`. - Slice { - prefix: Vec<Pat<'tcx>>, - slice: Option<Pat<'tcx>>, - suffix: Vec<Pat<'tcx>>, - }, - - /// Fixed match against an array; irrefutable. - Array { - prefix: Vec<Pat<'tcx>>, - slice: Option<Pat<'tcx>>, - suffix: Vec<Pat<'tcx>>, - }, - - /// An or-pattern, e.g. `p | q`. - /// Invariant: `pats.len() >= 2`. - Or { - pats: Vec<Pat<'tcx>>, - }, -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub struct PatRange<'tcx> { - pub lo: &'tcx ty::Const<'tcx>, - pub hi: &'tcx ty::Const<'tcx>, - pub end: RangeEnd, -} - -impl<'tcx> fmt::Display for Pat<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Printing lists is a chore. - let mut first = true; - let mut start_or_continue = |s| { - if first { - first = false; - "" - } else { - s - } - }; - let mut start_or_comma = || start_or_continue(", "); - - match *self.kind { - PatKind::Wild => write!(f, "_"), - PatKind::AscribeUserType { ref subpattern, .. } => write!(f, "{}: _", subpattern), - PatKind::Binding { mutability, name, mode, ref subpattern, .. } => { - let is_mut = match mode { - BindingMode::ByValue => mutability == Mutability::Mut, - BindingMode::ByRef(bk) => { - write!(f, "ref ")?; - matches!(bk, BorrowKind::Mut { .. }) - } - }; - if is_mut { - write!(f, "mut ")?; - } - write!(f, "{}", name)?; - if let Some(ref subpattern) = *subpattern { - write!(f, " @ {}", subpattern)?; - } - Ok(()) - } - PatKind::Variant { ref subpatterns, .. } | PatKind::Leaf { ref subpatterns } => { - let variant = match *self.kind { - PatKind::Variant { adt_def, variant_index, .. } => { - Some(&adt_def.variants[variant_index]) - } - _ => { - if let ty::Adt(adt, _) = self.ty.kind() { - if !adt.is_enum() { - Some(&adt.variants[VariantIdx::new(0)]) - } else { - None - } - } else { - None - } - } - }; - - if let Some(variant) = variant { - write!(f, "{}", variant.ident)?; - - // Only for Adt we can have `S {...}`, - // which we handle separately here. - if variant.ctor_kind == CtorKind::Fictive { - write!(f, " {{ ")?; - - let mut printed = 0; - for p in subpatterns { - if let PatKind::Wild = *p.pattern.kind { - continue; - } - let name = variant.fields[p.field.index()].ident; - write!(f, "{}{}: {}", start_or_comma(), name, p.pattern)?; - printed += 1; - } - - if printed < variant.fields.len() { - write!(f, "{}..", start_or_comma())?; - } - - return write!(f, " }}"); - } - } - - let num_fields = variant.map_or(subpatterns.len(), |v| v.fields.len()); - if num_fields != 0 || variant.is_none() { - write!(f, "(")?; - for i in 0..num_fields { - write!(f, "{}", start_or_comma())?; - - // Common case: the field is where we expect it. - if let Some(p) = subpatterns.get(i) { - if p.field.index() == i { - write!(f, "{}", p.pattern)?; - continue; - } - } - - // Otherwise, we have to go looking for it. - if let Some(p) = subpatterns.iter().find(|p| p.field.index() == i) { - write!(f, "{}", p.pattern)?; - } else { - write!(f, "_")?; - } - } - write!(f, ")")?; - } - - Ok(()) - } - PatKind::Deref { ref subpattern } => { - match self.ty.kind() { - ty::Adt(def, _) if def.is_box() => write!(f, "box ")?, - ty::Ref(_, _, mutbl) => { - write!(f, "&{}", mutbl.prefix_str())?; - } - _ => bug!("{} is a bad Deref pattern type", self.ty), - } - write!(f, "{}", subpattern) - } - PatKind::Constant { value } => write!(f, "{}", value), - PatKind::Range(PatRange { lo, hi, end }) => { - write!(f, "{}", lo)?; - write!(f, "{}", end)?; - write!(f, "{}", hi) - } - PatKind::Slice { ref prefix, ref slice, ref suffix } - | PatKind::Array { ref prefix, ref slice, ref suffix } => { - write!(f, "[")?; - for p in prefix { - write!(f, "{}{}", start_or_comma(), p)?; - } - if let Some(ref slice) = *slice { - write!(f, "{}", start_or_comma())?; - match *slice.kind { - PatKind::Wild => {} - _ => write!(f, "{}", slice)?, - } - write!(f, "..")?; - } - for p in suffix { - write!(f, "{}{}", start_or_comma(), p)?; - } - write!(f, "]") - } - PatKind::Or { ref pats } => { - for pat in pats { - write!(f, "{}{}", start_or_continue(" | "), pat)?; - } - Ok(()) - } - } - } -} - crate struct PatCtxt<'a, 'tcx> { crate tcx: TyCtxt<'tcx>, crate param_env: ty::ParamEnv<'tcx>, @@ -358,22 +43,20 @@ crate struct PatCtxt<'a, 'tcx> { include_lint_checks: bool, } -impl<'a, 'tcx> Pat<'tcx> { - crate fn from_hir( - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, - pat: &'tcx hir::Pat<'tcx>, - ) -> Self { - let mut pcx = PatCtxt::new(tcx, param_env, typeck_results); - let result = pcx.lower_pattern(pat); - if !pcx.errors.is_empty() { - let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors); - tcx.sess.delay_span_bug(pat.span, &msg); - } - debug!("Pat::from_hir({:?}) = {:?}", pat, result); - result - } +crate fn pat_from_hir<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + typeck_results: &'a ty::TypeckResults<'tcx>, + pat: &'tcx hir::Pat<'tcx>, +) -> Pat<'tcx> { + let mut pcx = PatCtxt::new(tcx, param_env, typeck_results); + let result = pcx.lower_pattern(pat); + if !pcx.errors.is_empty() { + let msg = format!("encountered errors lowering pattern: {:?}", pcx.errors); + tcx.sess.delay_span_bug(pat.span, &msg); + } + debug!("pat_from_hir({:?}) = {:?}", pat, result); + result } impl<'a, 'tcx> PatCtxt<'a, 'tcx> { diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index dce0df8473b..5d4eb75155a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -284,7 +284,6 @@ use self::Usefulness::*; use self::WitnessPreference::*; use super::deconstruct_pat::{Constructor, Fields, SplitWildcard}; -use super::{Pat, PatKind}; use super::{PatternFoldable, PatternFolder}; use rustc_data_structures::captures::Captures; @@ -293,6 +292,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_arena::TypedArena; use rustc_hir::def_id::DefId; use rustc_hir::HirId; +use rustc_middle::thir::{Pat, PatKind}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_span::Span; @@ -382,31 +382,29 @@ impl<'tcx> PatternFolder<'tcx> for LiteralExpander { } } -impl<'tcx> Pat<'tcx> { - pub(super) fn is_wildcard(&self) -> bool { - matches!(*self.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) - } +pub(super) fn is_wildcard(pat: &Pat<'_>) -> bool { + matches!(*pat.kind, PatKind::Binding { subpattern: None, .. } | PatKind::Wild) +} - fn is_or_pat(&self) -> bool { - matches!(*self.kind, PatKind::Or { .. }) - } +fn is_or_pat(pat: &Pat<'_>) -> bool { + matches!(*pat.kind, PatKind::Or { .. }) +} - /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. - fn expand_or_pat(&self) -> Vec<&Self> { - fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) { - if let PatKind::Or { pats } = pat.kind.as_ref() { - for pat in pats { - expand(pat, vec); - } - } else { - vec.push(pat) +/// Recursively expand this pattern into its subpatterns. Only useful for or-patterns. +fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { + fn expand<'p, 'tcx>(pat: &'p Pat<'tcx>, vec: &mut Vec<&'p Pat<'tcx>>) { + if let PatKind::Or { pats } = pat.kind.as_ref() { + for pat in pats { + expand(pat, vec); } + } else { + vec.push(pat) } - - let mut pats = Vec::new(); - expand(self, &mut pats); - pats } + + let mut pats = Vec::new(); + expand(pat, &mut pats); + pats } /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` @@ -451,7 +449,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { // Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an // or-pattern. Panics if `self` is empty. fn expand_or_pat<'a>(&'a self) -> impl Iterator<Item = PatStack<'p, 'tcx>> + Captures<'a> { - self.head().expand_or_pat().into_iter().map(move |pat| { + expand_or_pat(self.head()).into_iter().map(move |pat| { let mut new_patstack = PatStack::from_pattern(pat); new_patstack.pats.extend_from_slice(&self.pats[1..]); new_patstack @@ -525,7 +523,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively /// expands it. fn push(&mut self, row: PatStack<'p, 'tcx>) { - if !row.is_empty() && row.head().is_or_pat() { + if !row.is_empty() && is_or_pat(row.head()) { for row in row.expand_or_pat() { self.patterns.push(row); } @@ -760,7 +758,7 @@ impl<'p, 'tcx> SubPatSet<'p, 'tcx> { } } SubPatSet::Alt { subpats, pat, alt_count, .. } => { - let expanded = pat.expand_or_pat(); + let expanded = expand_or_pat(pat); for i in 0..*alt_count { let sub_set = subpats.get(&i).unwrap_or(&SubPatSet::Empty); if sub_set.is_empty() { @@ -1118,7 +1116,7 @@ fn is_useful<'p, 'tcx>( let pcx = PatCtxt { cx, ty, span: v.head().span, is_top_level }; // If the first pattern is an or-pattern, expand it. - let ret = if v.head().is_or_pat() { + let ret = if is_or_pat(v.head()) { debug!("expanding or-pattern"); let v_head = v.head(); let vs: Vec<_> = v.expand_or_pat().collect(); @@ -1174,7 +1172,7 @@ fn is_useful<'p, 'tcx>( #[derive(Clone, Copy)] crate struct MatchArm<'p, 'tcx> { /// The pattern must have been lowered through `check_match::MatchVisitor::lower_pattern`. - crate pat: &'p super::Pat<'tcx>, + crate pat: &'p Pat<'tcx>, crate hir_id: HirId, crate has_guard: bool, } @@ -1196,7 +1194,7 @@ crate struct UsefulnessReport<'p, 'tcx> { crate arm_usefulness: Vec<(MatchArm<'p, 'tcx>, Reachability)>, /// If the match is exhaustive, this is empty. If not, this contains witnesses for the lack of /// exhaustiveness. - crate non_exhaustiveness_witnesses: Vec<super::Pat<'tcx>>, + crate non_exhaustiveness_witnesses: Vec<Pat<'tcx>>, } /// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which @@ -1232,7 +1230,7 @@ crate fn compute_match_usefulness<'p, 'tcx>( }) .collect(); - let wild_pattern = cx.pattern_arena.alloc(super::Pat::wildcard_from_ty(scrut_ty)); + let wild_pattern = cx.pattern_arena.alloc(Pat::wildcard_from_ty(scrut_ty)); let v = PatStack::from_pattern(wild_pattern); let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, scrut_hir_id, false, true); let non_exhaustiveness_witnesses = match usefulness { diff --git a/compiler/rustc_mir_build/src/thir/visit.rs b/compiler/rustc_mir_build/src/thir/visit.rs index 9c5b07e2b2a..1a60b1de7fd 100644 --- a/compiler/rustc_mir_build/src/thir/visit.rs +++ b/compiler/rustc_mir_build/src/thir/visit.rs @@ -1,123 +1,125 @@ -use crate::thir::*; +use rustc_middle::thir::*; +use rustc_middle::ty::Const; -pub trait Visitor<'thir, 'tcx>: Sized { - fn visit_expr(&mut self, expr: &'thir Expr<'thir, 'tcx>) { +pub trait Visitor<'a, 'tcx: 'a>: Sized { + fn thir(&self) -> &'a Thir<'tcx>; + + fn visit_expr(&mut self, expr: &Expr<'tcx>) { walk_expr(self, expr); } - fn visit_stmt(&mut self, stmt: &'thir Stmt<'thir, 'tcx>) { + fn visit_stmt(&mut self, stmt: &Stmt<'tcx>) { walk_stmt(self, stmt); } - fn visit_block(&mut self, block: &Block<'thir, 'tcx>) { + fn visit_block(&mut self, block: &Block) { walk_block(self, block); } - fn visit_arm(&mut self, arm: &'thir Arm<'thir, 'tcx>) { + fn visit_arm(&mut self, arm: &Arm<'tcx>) { walk_arm(self, arm); } fn visit_const(&mut self, _cnst: &'tcx Const<'tcx>) {} } -pub fn walk_expr<'thir, 'tcx, V: Visitor<'thir, 'tcx>>( - visitor: &mut V, - expr: &'thir Expr<'thir, 'tcx>, -) { +pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Expr<'tcx>) { use ExprKind::*; match expr.kind { - Scope { value, region_scope: _, lint_level: _ } => visitor.visit_expr(value), - Box { value } => visitor.visit_expr(value), + Scope { value, region_scope: _, lint_level: _ } => { + visitor.visit_expr(&visitor.thir()[value]) + } + Box { value } => visitor.visit_expr(&visitor.thir()[value]), If { cond, then, else_opt } => { - visitor.visit_expr(cond); - visitor.visit_expr(then); + visitor.visit_expr(&visitor.thir()[cond]); + visitor.visit_expr(&visitor.thir()[then]); if let Some(else_expr) = else_opt { - visitor.visit_expr(else_expr); + visitor.visit_expr(&visitor.thir()[else_expr]); } } - Call { fun, args, ty: _, from_hir_call: _, fn_span: _ } => { - visitor.visit_expr(fun); - for arg in args { - visitor.visit_expr(arg); + Call { fun, ref args, ty: _, from_hir_call: _, fn_span: _ } => { + visitor.visit_expr(&visitor.thir()[fun]); + for &arg in &**args { + visitor.visit_expr(&visitor.thir()[arg]); } } - Deref { arg } => visitor.visit_expr(arg), + Deref { arg } => visitor.visit_expr(&visitor.thir()[arg]), Binary { lhs, rhs, op: _ } | LogicalOp { lhs, rhs, op: _ } => { - visitor.visit_expr(lhs); - visitor.visit_expr(rhs); - } - Unary { arg, op: _ } => visitor.visit_expr(arg), - Cast { source } => visitor.visit_expr(source), - Use { source } => visitor.visit_expr(source), - NeverToAny { source } => visitor.visit_expr(source), - Pointer { source, cast: _ } => visitor.visit_expr(source), - Loop { body } => visitor.visit_expr(body), - Match { scrutinee, arms } => { - visitor.visit_expr(scrutinee); - for arm in arms { - visitor.visit_arm(arm); + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[rhs]); + } + Unary { arg, op: _ } => visitor.visit_expr(&visitor.thir()[arg]), + Cast { source } => visitor.visit_expr(&visitor.thir()[source]), + Use { source } => visitor.visit_expr(&visitor.thir()[source]), + NeverToAny { source } => visitor.visit_expr(&visitor.thir()[source]), + Pointer { source, cast: _ } => visitor.visit_expr(&visitor.thir()[source]), + Loop { body } => visitor.visit_expr(&visitor.thir()[body]), + Match { scrutinee, ref arms } => { + visitor.visit_expr(&visitor.thir()[scrutinee]); + for &arm in &**arms { + visitor.visit_arm(&visitor.thir()[arm]); } } Block { ref body } => visitor.visit_block(body), Assign { lhs, rhs } | AssignOp { lhs, rhs, op: _ } => { - visitor.visit_expr(lhs); - visitor.visit_expr(rhs); + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[rhs]); } - Field { lhs, name: _ } => visitor.visit_expr(lhs), + Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), Index { lhs, index } => { - visitor.visit_expr(lhs); - visitor.visit_expr(index); + visitor.visit_expr(&visitor.thir()[lhs]); + visitor.visit_expr(&visitor.thir()[index]); } VarRef { id: _ } | UpvarRef { closure_def_id: _, var_hir_id: _ } => {} - Borrow { arg, borrow_kind: _ } => visitor.visit_expr(arg), - AddressOf { arg, mutability: _ } => visitor.visit_expr(arg), + Borrow { arg, borrow_kind: _ } => visitor.visit_expr(&visitor.thir()[arg]), + AddressOf { arg, mutability: _ } => visitor.visit_expr(&visitor.thir()[arg]), Break { value, label: _ } => { if let Some(value) = value { - visitor.visit_expr(value) + visitor.visit_expr(&visitor.thir()[value]) } } Continue { label: _ } => {} Return { value } => { if let Some(value) = value { - visitor.visit_expr(value) + visitor.visit_expr(&visitor.thir()[value]) } } ConstBlock { value } => visitor.visit_const(value), Repeat { value, count } => { - visitor.visit_expr(value); + visitor.visit_expr(&visitor.thir()[value]); visitor.visit_const(count); } - Array { fields } | Tuple { fields } => { - for field in fields { - visitor.visit_expr(field); + Array { ref fields } | Tuple { ref fields } => { + for &field in &**fields { + visitor.visit_expr(&visitor.thir()[field]); } } - Adt { fields, ref base, adt_def: _, variant_index: _, substs: _, user_ty: _ } => { - for field in fields { - visitor.visit_expr(field.expr); + Adt { ref fields, ref base, adt_def: _, variant_index: _, substs: _, user_ty: _ } => { + for field in &**fields { + visitor.visit_expr(&visitor.thir()[field.expr]); } if let Some(base) = base { - visitor.visit_expr(base.base); + visitor.visit_expr(&visitor.thir()[base.base]); } } PlaceTypeAscription { source, user_ty: _ } | ValueTypeAscription { source, user_ty: _ } => { - visitor.visit_expr(source) + visitor.visit_expr(&visitor.thir()[source]) } Closure { closure_id: _, substs: _, upvars: _, movability: _, fake_reads: _ } => {} Literal { literal, user_ty: _, const_id: _ } => visitor.visit_const(literal), StaticRef { literal, def_id: _ } => visitor.visit_const(literal), - InlineAsm { operands, template: _, options: _, line_spans: _ } => { - for op in operands { + InlineAsm { ref operands, template: _, options: _, line_spans: _ } => { + for op in &**operands { use InlineAsmOperand::*; match op { In { expr, reg: _ } | Out { expr: Some(expr), reg: _, late: _ } | InOut { expr, reg: _, late: _ } - | SymFn { expr } => visitor.visit_expr(expr), + | SymFn { expr } => visitor.visit_expr(&visitor.thir()[*expr]), SplitInOut { in_expr, out_expr, reg: _, late: _ } => { - visitor.visit_expr(in_expr); + visitor.visit_expr(&visitor.thir()[*in_expr]); if let Some(out_expr) = out_expr { - visitor.visit_expr(out_expr); + visitor.visit_expr(&visitor.thir()[*out_expr]); } } Out { expr: None, reg: _, late: _ } @@ -127,24 +129,21 @@ pub fn walk_expr<'thir, 'tcx, V: Visitor<'thir, 'tcx>>( } } ThreadLocalRef(_) => {} - LlvmInlineAsm { outputs, inputs, asm: _ } => { - for out_expr in outputs { - visitor.visit_expr(out_expr); + LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => { + for &out_expr in &**outputs { + visitor.visit_expr(&visitor.thir()[out_expr]); } - for in_expr in inputs { - visitor.visit_expr(in_expr); + for &in_expr in &**inputs { + visitor.visit_expr(&visitor.thir()[in_expr]); } } - Yield { value } => visitor.visit_expr(value), + Yield { value } => visitor.visit_expr(&visitor.thir()[value]), } } -pub fn walk_stmt<'thir, 'tcx, V: Visitor<'thir, 'tcx>>( - visitor: &mut V, - stmt: &'thir Stmt<'thir, 'tcx>, -) { +pub fn walk_stmt<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, stmt: &Stmt<'tcx>) { match stmt.kind { - StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(expr), + StmtKind::Expr { expr, scope: _ } => visitor.visit_expr(&visitor.thir()[expr]), StmtKind::Let { initializer, remainder_scope: _, @@ -153,34 +152,28 @@ pub fn walk_stmt<'thir, 'tcx, V: Visitor<'thir, 'tcx>>( lint_level: _, } => { if let Some(init) = initializer { - visitor.visit_expr(init); + visitor.visit_expr(&visitor.thir()[init]); } } } } -pub fn walk_block<'thir, 'tcx, V: Visitor<'thir, 'tcx>>( - visitor: &mut V, - block: &Block<'thir, 'tcx>, -) { - for stmt in block.stmts { - visitor.visit_stmt(stmt); +pub fn walk_block<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, block: &Block) { + for &stmt in &*block.stmts { + visitor.visit_stmt(&visitor.thir()[stmt]); } if let Some(expr) = block.expr { - visitor.visit_expr(expr); + visitor.visit_expr(&visitor.thir()[expr]); } } -pub fn walk_arm<'thir, 'tcx, V: Visitor<'thir, 'tcx>>( - visitor: &mut V, - arm: &'thir Arm<'thir, 'tcx>, -) { +pub fn walk_arm<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, arm: &Arm<'tcx>) { match arm.guard { - Some(Guard::If(expr)) => visitor.visit_expr(expr), + Some(Guard::If(expr)) => visitor.visit_expr(&visitor.thir()[expr]), Some(Guard::IfLet(ref _pat, expr)) => { - visitor.visit_expr(expr); + visitor.visit_expr(&visitor.thir()[expr]); } None => {} } - visitor.visit_expr(arm.body); + visitor.visit_expr(&visitor.thir()[arm.body]); } diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 077b19fa959..51df06bd989 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -3,8 +3,6 @@ #![feature(array_windows)] #![feature(crate_visibility_modifier)] #![feature(bindings_after_at)] -#![feature(iter_order_by)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(box_syntax)] #![feature(box_patterns)] #![recursion_limit = "256"] diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index c64fab0507c..54e6ff6272c 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1474,7 +1474,10 @@ impl<'a> Parser<'a> { self.sess.gated_spans.gate(sym::unnamed_fields, lo); } else { let err = if self.check_fn_front_matter(false) { - let _ = self.parse_fn(&mut Vec::new(), |_| true, lo); + // We use `parse_fn` to get a span for the function + if let Err(mut db) = self.parse_fn(&mut Vec::new(), |_| true, lo) { + db.delay_as_bug(); + } let mut err = self.struct_span_err( lo.to(self.prev_token.span), &format!("functions are not allowed in {} definitions", adt_ty), diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs index 35cfaae13a4..4c2bc6ebf31 100644 --- a/compiler/rustc_parse/src/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -1065,24 +1065,11 @@ impl<'a> Parser<'a> { } else if !delimited_only { if self.eat(&token::Eq) { let eq_span = self.prev_token.span; - let mut is_interpolated_expr = false; - if let token::Interpolated(nt) = &self.token.kind { - if let token::NtExpr(..) = **nt { - is_interpolated_expr = true; - } - } // Collect tokens because they are used during lowering to HIR. let expr = self.parse_expr_force_collect()?; let span = expr.span; - match &expr.kind { - // Not gated to support things like `doc = $expr` that work on stable. - _ if is_interpolated_expr => {} - ExprKind::Lit(lit) if lit.kind.is_unsuffixed() => {} - _ => self.sess.gated_spans.gate(sym::extended_key_value_attributes, span), - } - let token_kind = token::Interpolated(Lrc::new(token::NtExpr(expr))); MacArgs::Eq(eq_span, Token::new(token_kind, span)) } else { diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 50db69f4209..9d653de910f 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -10,7 +10,6 @@ test(attr(deny(warnings))) )] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(bool_to_option)] pub use Alignment::*; diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index cfc18062d53..118fcca4508 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -13,12 +13,13 @@ use crate::weak_lang_items; use rustc_middle::middle::cstore::ExternCrate; use rustc_middle::ty::TyCtxt; -use rustc_errors::struct_span_err; +use rustc_errors::{pluralize, struct_span_err}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::lang_items::{extract, ITEM_REFS}; use rustc_hir::{HirId, LangItem, LanguageItems, Target}; +use rustc_span::Span; use rustc_middle::ty::query::Providers; @@ -61,8 +62,7 @@ impl LanguageItemCollector<'tcx> { match ITEM_REFS.get(&value).cloned() { // Known lang item with attribute on correct target. Some((item_index, expected_target)) if actual_target == expected_target => { - let def_id = self.tcx.hir().local_def_id(hir_id); - self.collect_item(item_index, def_id.to_def_id()); + self.collect_item_extended(item_index, hir_id, span); } // Known lang item with attribute on incorrect target. Some((_, expected_target)) => { @@ -180,6 +180,127 @@ impl LanguageItemCollector<'tcx> { self.items.groups[group as usize].push(item_def_id); } } + + // Like collect_item() above, but also checks whether the lang item is declared + // with the right number of generic arguments if it is a trait. + fn collect_item_extended(&mut self, item_index: usize, hir_id: HirId, span: Span) { + let item_def_id = self.tcx.hir().local_def_id(hir_id).to_def_id(); + let lang_item = LangItem::from_u32(item_index as u32).unwrap(); + let name = lang_item.name(); + + self.collect_item(item_index, item_def_id); + + // Now check whether the lang_item has the expected number of generic + // arguments if it is a trait. Generally speaking, binary and indexing + // operations have one (for the RHS/index), unary operations have none, + // and the rest also have none except for the closure traits (one for + // the argument list), generators (one for the resume argument), + // ordering/equality relations (one for the RHS), and various conversion + // traits. + + let expected_num = match lang_item { + // Binary operations + LangItem::Add + | LangItem::Sub + | LangItem::Mul + | LangItem::Div + | LangItem::Rem + | LangItem::BitXor + | LangItem::BitAnd + | LangItem::BitOr + | LangItem::Shl + | LangItem::Shr + | LangItem::AddAssign + | LangItem::SubAssign + | LangItem::MulAssign + | LangItem::DivAssign + | LangItem::RemAssign + | LangItem::BitXorAssign + | LangItem::BitAndAssign + | LangItem::BitOrAssign + | LangItem::ShlAssign + | LangItem::ShrAssign + | LangItem::Index + | LangItem::IndexMut + + // Miscellaneous + | LangItem::Unsize + | LangItem::CoerceUnsized + | LangItem::DispatchFromDyn + | LangItem::Fn + | LangItem::FnMut + | LangItem::FnOnce + | LangItem::Generator + | LangItem::PartialEq + | LangItem::PartialOrd + => Some(1), + + // Unary operations + LangItem::Neg + | LangItem::Not + + // Miscellaneous + | LangItem::Deref + | LangItem::DerefMut + | LangItem::Sized + | LangItem::StructuralPeq + | LangItem::StructuralTeq + | LangItem::Copy + | LangItem::Clone + | LangItem::Sync + | LangItem::DiscriminantKind + | LangItem::PointeeTrait + | LangItem::Freeze + | LangItem::Drop + | LangItem::Receiver + | LangItem::Future + | LangItem::Unpin + | LangItem::Termination + | LangItem::Try + | LangItem::Send + | LangItem::UnwindSafe + | LangItem::RefUnwindSafe + => Some(0), + + // Not a trait + _ => None, + }; + + if let Some(expected_num) = expected_num { + let (actual_num, generics_span) = match self.tcx.hir().get(hir_id) { + hir::Node::Item(hir::Item { + kind: hir::ItemKind::Trait(_, _, generics, ..), + .. + }) => (generics.params.len(), generics.span), + _ => bug!("op/index/deref lang item target is not a trait: {:?}", lang_item), + }; + + if expected_num != actual_num { + // We are issuing E0718 "incorrect target" here, because while the + // item kind of the target is correct, the target is still wrong + // because of the wrong number of generic arguments. + struct_span_err!( + self.tcx.sess, + span, + E0718, + "`{}` language item must be applied to a trait with {} generic argument{}", + name, + expected_num, + pluralize!(expected_num) + ) + .span_label( + generics_span, + format!( + "this trait has {} generic argument{}, not {}", + actual_num, + pluralize!(actual_num), + expected_num + ), + ) + .emit(); + } + } + } } /// Traverses and collects all the lang items in all crates. diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 0be7ef7e12a..28633faa205 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -5,12 +5,11 @@ //! This API is completely unstable and subject to change. #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] -#![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(iter_zip)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] +#![feature(min_specialization)] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index f41e0e03706..29a0a3c48e5 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -828,7 +828,11 @@ impl Visitor<'tcx> for Checker<'tcx> { fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, id: hir::HirId) { if let Some(def_id) = path.res.opt_def_id() { - self.tcx.check_stability(def_id, Some(id), path.span, None) + let method_span = match path.segments { + [.., _, last] => Some(last.ident.span), + _ => None, + }; + self.tcx.check_stability(def_id, Some(id), path.span, method_span) } intravisit::walk_path(self, path) } diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 1342762bb07..e64f12ef48f 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,7 +1,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(control_flow_enum)] #![feature(try_blocks)] #![feature(associated_type_defaults)] diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 00d886000fa..4175fb6925a 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -2,13 +2,9 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] -#![feature(exhaustive_patterns)] #![feature(nll)] #![feature(min_specialization)] -#![feature(crate_visibility_modifier)] -#![feature(once_cell)] #![feature(rustc_attrs)] -#![feature(never_type)] #![recursion_limit = "256"] #[macro_use] @@ -26,7 +22,7 @@ use rustc_middle::ty::query::{query_keys, query_storage, query_stored, query_val use rustc_middle::ty::query::{Providers, QueryEngine}; use rustc_middle::ty::{self, TyCtxt}; use rustc_serialize::opaque; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; #[macro_use] mod plumbing; diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index c789aa2fa59..b4191c135b4 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -3,7 +3,7 @@ //! manage the caches, and so forth. use super::queries; -use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeExt, DepNodeIndex, SerializedDepNodeIndex}; +use rustc_middle::dep_graph::{DepKind, DepNode, DepNodeIndex, SerializedDepNodeIndex}; use rustc_middle::ty::query::on_disk_cache; use rustc_middle::ty::tls::{self, ImplicitCtxt}; use rustc_middle::ty::{self, TyCtxt}; @@ -14,7 +14,7 @@ use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; use rustc_serialize::opaque; -use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::def_id::LocalDefId; #[derive(Copy, Clone)] pub struct QueryCtxt<'tcx> { @@ -25,6 +25,7 @@ pub struct QueryCtxt<'tcx> { impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> { type Target = TyCtxt<'tcx>; + #[inline] fn deref(&self) -> &Self::Target { &self.tcx } @@ -42,10 +43,6 @@ impl HasDepContext for QueryCtxt<'tcx> { } impl QueryContext for QueryCtxt<'tcx> { - fn def_path_str(&self, def_id: DefId) -> String { - self.tcx.def_path_str(def_id) - } - fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>> { tls::with_related_context(**self, |icx| icx.query) } @@ -60,39 +57,6 @@ impl QueryContext for QueryCtxt<'tcx> { } fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool { - // FIXME: This match is just a workaround for incremental bugs and should - // be removed. https://github.com/rust-lang/rust/issues/62649 is one such - // bug that must be fixed before removing this. - match dep_node.kind { - DepKind::hir_owner | DepKind::hir_owner_nodes => { - if let Some(def_id) = dep_node.extract_def_id(**self) { - let def_id = def_id.expect_local(); - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); - if def_id != hir_id.owner { - // This `DefPath` does not have a - // corresponding `DepNode` (e.g. a - // struct field), and the ` DefPath` - // collided with the `DefPath` of a - // proper item that existed in the - // previous compilation session. - // - // Since the given `DefPath` does not - // denote the item that previously - // existed, we just fail to mark green. - return false; - } - } else { - // If the node does not exist anymore, we - // just fail to mark green. - return false; - } - } - _ => { - // For other kinds of nodes it's OK to be - // forced. - } - } - debug!("try_force_from_dep_node({:?}) --- trying to force", dep_node); // We must avoid ever having to call `force_from_dep_node()` for a @@ -457,20 +421,7 @@ macro_rules! define_queries { } fn force_from_dep_node(tcx: QueryCtxt<'_>, dep_node: &DepNode) -> bool { - if is_anon { - return false; - } - - if !can_reconstruct_query_key() { - return false; - } - - if let Some(key) = recover(*tcx, dep_node) { - force_query::<queries::$name<'_>, _>(tcx, key, DUMMY_SP, *dep_node); - return true; - } - - false + force_query::<queries::$name<'_>, _>(tcx, dep_node) } fn try_load_from_on_disk_cache(tcx: QueryCtxt<'_>, dep_node: &DepNode) { diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 2517793ecea..95edc1e93a5 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -61,7 +61,7 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { match def_key.disambiguated_data.data { DefPathData::CrateRoot => { - crate_name = self.tcx.original_crate_name(def_id.krate).as_str(); + crate_name = self.tcx.crate_name(def_id.krate).as_str(); name = &*crate_name; dis = ""; end_index = 3; diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index 7a0fc320663..71e67dfee53 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -19,9 +19,8 @@ use std::marker::PhantomData; use std::mem; use std::sync::atomic::Ordering::Relaxed; -use super::prev::PreviousDepGraph; use super::query::DepGraphQuery; -use super::serialized::{GraphEncoder, SerializedDepNodeIndex}; +use super::serialized::{GraphEncoder, SerializedDepGraph, SerializedDepNodeIndex}; use super::{DepContext, DepKind, DepNode, HasDepContext, WorkProductId}; use crate::query::QueryContext; @@ -45,6 +44,7 @@ rustc_index::newtype_index! { impl DepNodeIndex { pub const INVALID: DepNodeIndex = DepNodeIndex::MAX; + pub const SINGLETON_DEPENDENCYLESS_ANON_NODE: DepNodeIndex = DepNodeIndex::from_u32(0); } impl std::convert::From<DepNodeIndex> for QueryInvocationId { @@ -78,7 +78,7 @@ struct DepGraphData<K: DepKind> { /// The dep-graph from the previous compilation session. It contains all /// nodes and edges as well as all fingerprints of nodes that have them. - previous: PreviousDepGraph<K>, + previous: SerializedDepGraph<K>, colors: DepNodeColorMap, @@ -109,7 +109,8 @@ where impl<K: DepKind> DepGraph<K> { pub fn new( - prev_graph: PreviousDepGraph<K>, + profiler: &SelfProfilerRef, + prev_graph: SerializedDepGraph<K>, prev_work_products: FxHashMap<WorkProductId, WorkProduct>, encoder: FileEncoder, record_graph: bool, @@ -117,16 +118,23 @@ impl<K: DepKind> DepGraph<K> { ) -> DepGraph<K> { let prev_graph_node_count = prev_graph.node_count(); + let current = + CurrentDepGraph::new(prev_graph_node_count, encoder, record_graph, record_stats); + + // Instantiate a dependy-less node only once for anonymous queries. + let _green_node_index = current.intern_new_node( + profiler, + DepNode { kind: DepKind::NULL, hash: current.anon_id_seed.into() }, + smallvec![], + Fingerprint::ZERO, + ); + debug_assert_eq!(_green_node_index, DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE); + DepGraph { data: Some(Lrc::new(DepGraphData { previous_work_products: prev_work_products, dep_node_debug: Default::default(), - current: CurrentDepGraph::new( - prev_graph_node_count, - encoder, - record_graph, - record_stats, - ), + current, emitting_diagnostics: Default::default(), emitting_diagnostics_cond_var: Condvar::new(), previous: prev_graph, @@ -288,30 +296,47 @@ impl<K: DepKind> DepGraph<K> { let task_deps = Lock::new(TaskDeps::default()); let result = K::with_deps(Some(&task_deps), op); let task_deps = task_deps.into_inner(); + let task_deps = task_deps.reads; + + let dep_node_index = match task_deps.len() { + 0 => { + // Because the dep-node id of anon nodes is computed from the sets of its + // dependencies we already know what the ID of this dependency-less node is + // going to be (i.e. equal to the precomputed + // `SINGLETON_DEPENDENCYLESS_ANON_NODE`). As a consequence we can skip creating + // a `StableHasher` and sending the node through interning. + DepNodeIndex::SINGLETON_DEPENDENCYLESS_ANON_NODE + } + 1 => { + // When there is only one dependency, don't bother creating a node. + task_deps[0] + } + _ => { + // The dep node indices are hashed here instead of hashing the dep nodes of the + // dependencies. These indices may refer to different nodes per session, but this isn't + // a problem here because we that ensure the final dep node hash is per session only by + // combining it with the per session random number `anon_id_seed`. This hash only need + // to map the dependencies to a single value on a per session basis. + let mut hasher = StableHasher::new(); + task_deps.hash(&mut hasher); + + let target_dep_node = DepNode { + kind: dep_kind, + // Fingerprint::combine() is faster than sending Fingerprint + // through the StableHasher (at least as long as StableHasher + // is so slow). + hash: data.current.anon_id_seed.combine(hasher.finish()).into(), + }; - // The dep node indices are hashed here instead of hashing the dep nodes of the - // dependencies. These indices may refer to different nodes per session, but this isn't - // a problem here because we that ensure the final dep node hash is per session only by - // combining it with the per session random number `anon_id_seed`. This hash only need - // to map the dependencies to a single value on a per session basis. - let mut hasher = StableHasher::new(); - task_deps.reads.hash(&mut hasher); - - let target_dep_node = DepNode { - kind: dep_kind, - // Fingerprint::combine() is faster than sending Fingerprint - // through the StableHasher (at least as long as StableHasher - // is so slow). - hash: data.current.anon_id_seed.combine(hasher.finish()).into(), + data.current.intern_new_node( + cx.profiler(), + target_dep_node, + task_deps, + Fingerprint::ZERO, + ) + } }; - let dep_node_index = data.current.intern_new_node( - cx.profiler(), - target_dep_node, - task_deps.reads, - Fingerprint::ZERO, - ); - (result, dep_node_index) } else { (op(), self.next_virtual_depnode_index()) @@ -488,6 +513,117 @@ impl<K: DepKind> DepGraph<K> { } } + fn try_mark_parent_green<Ctxt: QueryContext<DepKind = K>>( + &self, + tcx: Ctxt, + data: &DepGraphData<K>, + parent_dep_node_index: SerializedDepNodeIndex, + dep_node: &DepNode<K>, + ) -> Option<()> { + let dep_dep_node_color = data.colors.get(parent_dep_node_index); + let dep_dep_node = &data.previous.index_to_node(parent_dep_node_index); + + match dep_dep_node_color { + Some(DepNodeColor::Green(_)) => { + // This dependency has been marked as green before, we are + // still fine and can continue with checking the other + // dependencies. + debug!( + "try_mark_previous_green({:?}) --- found dependency {:?} to \ + be immediately green", + dep_node, dep_dep_node, + ); + return Some(()); + } + Some(DepNodeColor::Red) => { + // We found a dependency the value of which has changed + // compared to the previous compilation session. We cannot + // mark the DepNode as green and also don't need to bother + // with checking any of the other dependencies. + debug!( + "try_mark_previous_green({:?}) - END - dependency {:?} was immediately red", + dep_node, dep_dep_node, + ); + return None; + } + None => {} + } + + // We don't know the state of this dependency. If it isn't + // an eval_always node, let's try to mark it green recursively. + if !dep_dep_node.kind.is_eval_always() { + debug!( + "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \ + is unknown, trying to mark it green", + dep_node, dep_dep_node, dep_dep_node.hash, + ); + + let node_index = + self.try_mark_previous_green(tcx, data, parent_dep_node_index, dep_dep_node); + if node_index.is_some() { + debug!( + "try_mark_previous_green({:?}) --- managed to MARK dependency {:?} as green", + dep_node, dep_dep_node + ); + return Some(()); + } + } + + // We failed to mark it green, so we try to force the query. + debug!( + "try_mark_previous_green({:?}) --- trying to force dependency {:?}", + dep_node, dep_dep_node + ); + if !tcx.try_force_from_dep_node(dep_dep_node) { + // The DepNode could not be forced. + debug!( + "try_mark_previous_green({:?}) - END - dependency {:?} could not be forced", + dep_node, dep_dep_node + ); + return None; + } + + let dep_dep_node_color = data.colors.get(parent_dep_node_index); + + match dep_dep_node_color { + Some(DepNodeColor::Green(_)) => { + debug!( + "try_mark_previous_green({:?}) --- managed to FORCE dependency {:?} to green", + dep_node, dep_dep_node + ); + return Some(()); + } + Some(DepNodeColor::Red) => { + debug!( + "try_mark_previous_green({:?}) - END - dependency {:?} was red after forcing", + dep_node, dep_dep_node + ); + return None; + } + None => {} + } + + if !tcx.dep_context().sess().has_errors_or_delayed_span_bugs() { + panic!("try_mark_previous_green() - Forcing the DepNode should have set its color") + } + + // If the query we just forced has resulted in + // some kind of compilation error, we cannot rely on + // the dep-node color having been properly updated. + // This means that the query system has reached an + // invalid state. We let the compiler continue (by + // returning `None`) so it can emit error messages + // and wind down, but rely on the fact that this + // invalid state will not be persisted to the + // incremental compilation cache because of + // compilation errors being present. + debug!( + "try_mark_previous_green({:?}) - END - dependency {:?} resulted in compilation error", + dep_node, dep_dep_node + ); + return None; + } + /// Try to mark a dep-node which existed in the previous compilation session as green. fn try_mark_previous_green<Ctxt: QueryContext<DepKind = K>>( &self, @@ -512,123 +648,7 @@ impl<K: DepKind> DepGraph<K> { let prev_deps = data.previous.edge_targets_from(prev_dep_node_index); for &dep_dep_node_index in prev_deps { - let dep_dep_node_color = data.colors.get(dep_dep_node_index); - - match dep_dep_node_color { - Some(DepNodeColor::Green(_)) => { - // This dependency has been marked as green before, we are - // still fine and can continue with checking the other - // dependencies. - debug!( - "try_mark_previous_green({:?}) --- found dependency {:?} to \ - be immediately green", - dep_node, - data.previous.index_to_node(dep_dep_node_index) - ); - } - Some(DepNodeColor::Red) => { - // We found a dependency the value of which has changed - // compared to the previous compilation session. We cannot - // mark the DepNode as green and also don't need to bother - // with checking any of the other dependencies. - debug!( - "try_mark_previous_green({:?}) - END - dependency {:?} was \ - immediately red", - dep_node, - data.previous.index_to_node(dep_dep_node_index) - ); - return None; - } - None => { - let dep_dep_node = &data.previous.index_to_node(dep_dep_node_index); - - // We don't know the state of this dependency. If it isn't - // an eval_always node, let's try to mark it green recursively. - if !dep_dep_node.kind.is_eval_always() { - debug!( - "try_mark_previous_green({:?}) --- state of dependency {:?} ({}) \ - is unknown, trying to mark it green", - dep_node, dep_dep_node, dep_dep_node.hash, - ); - - let node_index = self.try_mark_previous_green( - tcx, - data, - dep_dep_node_index, - dep_dep_node, - ); - if node_index.is_some() { - debug!( - "try_mark_previous_green({:?}) --- managed to MARK \ - dependency {:?} as green", - dep_node, dep_dep_node - ); - continue; - } - } - - // We failed to mark it green, so we try to force the query. - debug!( - "try_mark_previous_green({:?}) --- trying to force \ - dependency {:?}", - dep_node, dep_dep_node - ); - if tcx.try_force_from_dep_node(dep_dep_node) { - let dep_dep_node_color = data.colors.get(dep_dep_node_index); - - match dep_dep_node_color { - Some(DepNodeColor::Green(_)) => { - debug!( - "try_mark_previous_green({:?}) --- managed to \ - FORCE dependency {:?} to green", - dep_node, dep_dep_node - ); - } - Some(DepNodeColor::Red) => { - debug!( - "try_mark_previous_green({:?}) - END - \ - dependency {:?} was red after forcing", - dep_node, dep_dep_node - ); - return None; - } - None => { - if !tcx.dep_context().sess().has_errors_or_delayed_span_bugs() { - panic!( - "try_mark_previous_green() - Forcing the DepNode \ - should have set its color" - ) - } else { - // If the query we just forced has resulted in - // some kind of compilation error, we cannot rely on - // the dep-node color having been properly updated. - // This means that the query system has reached an - // invalid state. We let the compiler continue (by - // returning `None`) so it can emit error messages - // and wind down, but rely on the fact that this - // invalid state will not be persisted to the - // incremental compilation cache because of - // compilation errors being present. - debug!( - "try_mark_previous_green({:?}) - END - \ - dependency {:?} resulted in compilation error", - dep_node, dep_dep_node - ); - return None; - } - } - } - } else { - // The DepNode could not be forced. - debug!( - "try_mark_previous_green({:?}) - END - dependency {:?} \ - could not be forced", - dep_node, dep_dep_node - ); - return None; - } - } - } + self.try_mark_parent_green(tcx, data, dep_dep_node_index, dep_node)? } // If we got here without hitting a `return` that means that all @@ -797,7 +817,7 @@ impl<K: DepKind> DepGraph<K> { } } - fn next_virtual_depnode_index(&self) -> DepNodeIndex { + pub(crate) fn next_virtual_depnode_index(&self) -> DepNodeIndex { let index = self.virtual_dep_node_index.fetch_add(1, Relaxed); DepNodeIndex::from_u32(index) } @@ -857,7 +877,7 @@ rustc_index::newtype_index! { /// For this reason, we avoid storing `DepNode`s more than once as map /// keys. The `new_node_to_index` map only contains nodes not in the previous /// graph, and we map nodes in the previous graph to indices via a two-step -/// mapping. `PreviousDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`, +/// mapping. `SerializedDepGraph` maps from `DepNode` to `SerializedDepNodeIndex`, /// and the `prev_index_to_index` vector (which is more compact and faster than /// using a map) maps from `SerializedDepNodeIndex` to `DepNodeIndex`. /// @@ -982,7 +1002,7 @@ impl<K: DepKind> CurrentDepGraph<K> { fn intern_node( &self, profiler: &SelfProfilerRef, - prev_graph: &PreviousDepGraph<K>, + prev_graph: &SerializedDepGraph<K>, key: DepNode<K>, edges: EdgesVec, fingerprint: Option<Fingerprint>, @@ -1080,7 +1100,7 @@ impl<K: DepKind> CurrentDepGraph<K> { fn promote_node_and_deps_to_current( &self, profiler: &SelfProfilerRef, - prev_graph: &PreviousDepGraph<K>, + prev_graph: &SerializedDepGraph<K>, prev_index: SerializedDepNodeIndex, ) -> DepNodeIndex { self.debug_assert_not_in_new_nodes(prev_graph, prev_index); @@ -1112,7 +1132,7 @@ impl<K: DepKind> CurrentDepGraph<K> { #[inline] fn debug_assert_not_in_new_nodes( &self, - prev_graph: &PreviousDepGraph<K>, + prev_graph: &SerializedDepGraph<K>, prev_index: SerializedDepNodeIndex, ) { let node = &prev_graph.index_to_node(prev_index); diff --git a/compiler/rustc_query_system/src/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs index 1b6ecf3e637..15e2633c4f1 100644 --- a/compiler/rustc_query_system/src/dep_graph/mod.rs +++ b/compiler/rustc_query_system/src/dep_graph/mod.rs @@ -1,13 +1,11 @@ pub mod debug; mod dep_node; mod graph; -mod prev; mod query; mod serialized; pub use dep_node::{DepNode, DepNodeParams, WorkProductId}; pub use graph::{hash_result, DepGraph, DepNodeColor, DepNodeIndex, TaskDeps, WorkProduct}; -pub use prev::PreviousDepGraph; pub use query::DepGraphQuery; pub use serialized::{SerializedDepGraph, SerializedDepNodeIndex}; diff --git a/compiler/rustc_query_system/src/dep_graph/prev.rs b/compiler/rustc_query_system/src/dep_graph/prev.rs deleted file mode 100644 index 6303bbf53b9..00000000000 --- a/compiler/rustc_query_system/src/dep_graph/prev.rs +++ /dev/null @@ -1,56 +0,0 @@ -use super::serialized::{SerializedDepGraph, SerializedDepNodeIndex}; -use super::{DepKind, DepNode}; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::FxHashMap; - -#[derive(Debug)] -pub struct PreviousDepGraph<K: DepKind> { - data: SerializedDepGraph<K>, - index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>, -} - -impl<K: DepKind> Default for PreviousDepGraph<K> { - fn default() -> Self { - PreviousDepGraph { data: Default::default(), index: Default::default() } - } -} - -impl<K: DepKind> PreviousDepGraph<K> { - pub fn new(data: SerializedDepGraph<K>) -> PreviousDepGraph<K> { - let index: FxHashMap<_, _> = - data.nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect(); - PreviousDepGraph { data, index } - } - - #[inline] - pub fn edge_targets_from( - &self, - dep_node_index: SerializedDepNodeIndex, - ) -> &[SerializedDepNodeIndex] { - self.data.edge_targets_from(dep_node_index) - } - - #[inline] - pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> { - self.data.nodes[dep_node_index] - } - - #[inline] - pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> { - self.index.get(dep_node).cloned() - } - - #[inline] - pub fn fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> { - self.index.get(dep_node).map(|&node_index| self.data.fingerprints[node_index]) - } - - #[inline] - pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint { - self.data.fingerprints[dep_node_index] - } - - pub fn node_count(&self) -> usize { - self.index.len() - } -} diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs index 6f3d1fb7199..6a84a28be66 100644 --- a/compiler/rustc_query_system/src/dep_graph/serialized.rs +++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs @@ -37,17 +37,19 @@ rustc_index::newtype_index! { #[derive(Debug)] pub struct SerializedDepGraph<K: DepKind> { /// The set of all DepNodes in the graph - pub nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>, + nodes: IndexVec<SerializedDepNodeIndex, DepNode<K>>, /// The set of all Fingerprints in the graph. Each Fingerprint corresponds to /// the DepNode at the same index in the nodes vector. - pub fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>, + fingerprints: IndexVec<SerializedDepNodeIndex, Fingerprint>, /// For each DepNode, stores the list of edges originating from that /// DepNode. Encoded as a [start, end) pair indexing into edge_list_data, /// which holds the actual DepNodeIndices of the target nodes. - pub edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>, + edge_list_indices: IndexVec<SerializedDepNodeIndex, (u32, u32)>, /// A flattened list of all edge targets in the graph. Edge sources are /// implicit in edge_list_indices. - pub edge_list_data: Vec<SerializedDepNodeIndex>, + edge_list_data: Vec<SerializedDepNodeIndex>, + /// Reciprocal map to `nodes`. + index: FxHashMap<DepNode<K>, SerializedDepNodeIndex>, } impl<K: DepKind> Default for SerializedDepGraph<K> { @@ -57,6 +59,7 @@ impl<K: DepKind> Default for SerializedDepGraph<K> { fingerprints: Default::default(), edge_list_indices: Default::default(), edge_list_data: Default::default(), + index: Default::default(), } } } @@ -67,6 +70,30 @@ impl<K: DepKind> SerializedDepGraph<K> { let targets = self.edge_list_indices[source]; &self.edge_list_data[targets.0 as usize..targets.1 as usize] } + + #[inline] + pub fn index_to_node(&self, dep_node_index: SerializedDepNodeIndex) -> DepNode<K> { + self.nodes[dep_node_index] + } + + #[inline] + pub fn node_to_index_opt(&self, dep_node: &DepNode<K>) -> Option<SerializedDepNodeIndex> { + self.index.get(dep_node).cloned() + } + + #[inline] + pub fn fingerprint_of(&self, dep_node: &DepNode<K>) -> Option<Fingerprint> { + self.index.get(dep_node).map(|&node_index| self.fingerprints[node_index]) + } + + #[inline] + pub fn fingerprint_by_index(&self, dep_node_index: SerializedDepNodeIndex) -> Fingerprint { + self.fingerprints[dep_node_index] + } + + pub fn node_count(&self) -> usize { + self.index.len() + } } impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder<'a>> @@ -121,7 +148,10 @@ impl<'a, K: DepKind + Decodable<opaque::Decoder<'a>>> Decodable<opaque::Decoder< })?; } - Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data }) + let index: FxHashMap<_, _> = + nodes.iter_enumerated().map(|(idx, &dep_node)| (dep_node, idx)).collect(); + + Ok(SerializedDepGraph { nodes, fingerprints, edge_list_indices, edge_list_data, index }) } } diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index be72baefb9e..0d4fb34265c 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -1,11 +1,8 @@ #![feature(bool_to_option)] -#![feature(const_panic)] #![feature(core_intrinsics)] -#![feature(drain_filter)] #![feature(hash_raw_entry)] #![feature(iter_zip)] #![feature(min_specialization)] -#![feature(stmt_expr_attributes)] #[macro_use] extern crate tracing; diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index aef8a13ccef..927e8117f05 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -19,7 +19,6 @@ use crate::dep_graph::{DepNode, DepNodeIndex, HasDepContext, SerializedDepNodeIn use rustc_data_structures::sync::Lock; use rustc_data_structures::thin_vec::ThinVec; use rustc_errors::Diagnostic; -use rustc_span::def_id::DefId; use rustc_span::Span; /// Description of a frame in the query stack. @@ -64,9 +63,6 @@ impl QueryStackFrame { } pub trait QueryContext: HasDepContext { - /// Get string representation from DefPath. - fn def_path_str(&self, def_id: DefId) -> String; - /// Get the query information from the TLS context. fn current_query_job(&self) -> Option<QueryJobId<Self::DepKind>>; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 39dfdd78cc4..c1f9fa39e98 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -2,7 +2,7 @@ //! generate the actual methods on tcx which find and execute the provider, //! manage the caches, and so forth. -use crate::dep_graph::{DepContext, DepKind, DepNode}; +use crate::dep_graph::{DepContext, DepKind, DepNode, DepNodeParams}; use crate::dep_graph::{DepNodeIndex, SerializedDepNodeIndex}; use crate::query::caches::QueryCache; use crate::query::config::{QueryDescription, QueryVtable, QueryVtableExt}; @@ -19,7 +19,7 @@ use rustc_data_structures::thin_vec::ThinVec; #[cfg(not(parallel_compiler))] use rustc_errors::DiagnosticBuilder; use rustc_errors::{Diagnostic, FatalError}; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::collections::hash_map::Entry; use std::fmt::Debug; use std::hash::{Hash, Hasher}; @@ -431,7 +431,7 @@ fn try_execute_query<CTX, C>( ) -> C::Stored where C: QueryCache, - C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>, + C::Key: DepNodeParams<CTX::DepContext>, CTX: QueryContext, { let job = match JobOwner::<'_, CTX::DepKind, C>::try_start( @@ -452,11 +452,15 @@ where } }; - // Fast path for when incr. comp. is off. `to_dep_node` is - // expensive for some `DepKind`s. - if !tcx.dep_context().dep_graph().is_fully_enabled() { - let null_dep_node = DepNode::new_no_params(DepKind::NULL); - return force_query_with_job(tcx, key, job, null_dep_node, query).0; + let dep_graph = tcx.dep_context().dep_graph(); + + // Fast path for when incr. comp. is off. + if !dep_graph.is_fully_enabled() { + let prof_timer = tcx.dep_context().profiler().query_provider(); + let result = tcx.start_query(job.id, None, || query.compute(tcx, key)); + let dep_node_index = dep_graph.next_virtual_depnode_index(); + prof_timer.finish_with_query_invocation_id(dep_node_index.into()); + return job.complete(result, dep_node_index); } if query.anon { @@ -464,17 +468,14 @@ where let ((result, dep_node_index), diagnostics) = with_diagnostics(|diagnostics| { tcx.start_query(job.id, diagnostics, || { - tcx.dep_context().dep_graph().with_anon_task( - *tcx.dep_context(), - query.dep_kind, - || query.compute(tcx, key), - ) + dep_graph + .with_anon_task(*tcx.dep_context(), query.dep_kind, || query.compute(tcx, key)) }) }); prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - tcx.dep_context().dep_graph().read_index(dep_node_index); + dep_graph.read_index(dep_node_index); if unlikely!(!diagnostics.is_empty()) { tcx.store_diagnostics_for_anon_node(dep_node_index, diagnostics); @@ -490,7 +491,7 @@ where // promoted to the current session during // `try_mark_green()`, so we can ignore them here. let loaded = tcx.start_query(job.id, None, || { - let marked = tcx.dep_context().dep_graph().try_mark_green_and_read(tcx, &dep_node); + let marked = dep_graph.try_mark_green_and_read(tcx, &dep_node); marked.map(|(prev_dep_node_index, dep_node_index)| { ( load_from_disk_and_cache_in_memory( @@ -511,7 +512,7 @@ where } let (result, dep_node_index) = force_query_with_job(tcx, key, job, dep_node, query); - tcx.dep_context().dep_graph().read_index(dep_node_index); + dep_graph.read_index(dep_node_index); result } @@ -693,7 +694,7 @@ fn get_query_impl<CTX, C>( where CTX: QueryContext, C: QueryCache, - C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>, + C::Key: DepNodeParams<CTX::DepContext>, { try_execute_query(tcx, state, cache, span, key, lookup, query) } @@ -743,15 +744,28 @@ fn force_query_impl<CTX, C>( tcx: CTX, state: &QueryState<CTX::DepKind, C::Key>, cache: &QueryCacheStore<C>, - key: C::Key, - span: Span, dep_node: DepNode<CTX::DepKind>, query: &QueryVtable<CTX, C::Key, C::Value>, -) where +) -> bool +where C: QueryCache, - C::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>, + C::Key: DepNodeParams<CTX::DepContext>, CTX: QueryContext, { + debug_assert!(!query.anon); + + if !<C::Key as DepNodeParams<CTX::DepContext>>::can_reconstruct_query_key() { + return false; + } + + let key = if let Some(key) = + <C::Key as DepNodeParams<CTX::DepContext>>::recover(*tcx.dep_context(), &dep_node) + { + key + } else { + return false; + }; + // We may be concurrently trying both execute and force a query. // Ensure that only one of them runs the query. let cached = cache.cache.lookup(cache, &key, |_, index| { @@ -765,7 +779,7 @@ fn force_query_impl<CTX, C>( }); let lookup = match cached { - Ok(()) => return, + Ok(()) => return true, Err(lookup) => lookup, }; @@ -773,17 +787,20 @@ fn force_query_impl<CTX, C>( tcx, state, cache, - span, + DUMMY_SP, key.clone(), lookup, query, ) { TryGetJob::NotYetStarted(job) => job, - TryGetJob::Cycle(_) => return, + TryGetJob::Cycle(_) => return true, #[cfg(parallel_compiler)] - TryGetJob::JobCompleted(_) => return, + TryGetJob::JobCompleted(_) => return true, }; + force_query_with_job(tcx, key, job, dep_node, query); + + true } pub enum QueryMode { @@ -800,7 +817,7 @@ pub fn get_query<Q, CTX>( ) -> Option<Q::Stored> where Q: QueryDescription<CTX>, - Q::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>, + Q::Key: DepNodeParams<CTX::DepContext>, CTX: QueryContext, { let query = &Q::VTABLE; @@ -816,11 +833,15 @@ where Some(value) } -pub fn force_query<Q, CTX>(tcx: CTX, key: Q::Key, span: Span, dep_node: DepNode<CTX::DepKind>) +pub fn force_query<Q, CTX>(tcx: CTX, dep_node: &DepNode<CTX::DepKind>) -> bool where Q: QueryDescription<CTX>, - Q::Key: crate::dep_graph::DepNodeParams<CTX::DepContext>, + Q::Key: DepNodeParams<CTX::DepContext>, CTX: QueryContext, { - force_query_impl(tcx, Q::query_state(tcx), Q::query_cache(tcx), key, span, dep_node, &Q::VTABLE) + if Q::ANON { + return false; + } + + force_query_impl(tcx, Q::query_state(tcx), Q::query_cache(tcx), *dep_node, &Q::VTABLE) } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 6ea46f5c528..03d94f43897 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -425,27 +425,32 @@ impl<'a> Resolver<'a> { } err } - ResolutionError::BindingShadowsSomethingUnacceptable(what_binding, name, binding) => { - let res = binding.res(); - let shadows_what = res.descr(); + ResolutionError::BindingShadowsSomethingUnacceptable { + shadowing_binding_descr, + name, + participle, + article, + shadowed_binding_descr, + shadowed_binding_span, + } => { let mut err = struct_span_err!( self.session, span, E0530, "{}s cannot shadow {}s", - what_binding, - shadows_what + shadowing_binding_descr, + shadowed_binding_descr, ); err.span_label( span, - format!("cannot be named the same as {} {}", res.article(), shadows_what), + format!("cannot be named the same as {} {}", article, shadowed_binding_descr), ); - let participle = if binding.is_import() { "imported" } else { "defined" }; - let msg = format!("the {} `{}` is {} here", shadows_what, name, participle); - err.span_label(binding.span, msg); + let msg = + format!("the {} `{}` is {} here", shadowed_binding_descr, name, participle); + err.span_label(shadowed_binding_span, msg); err } - ResolutionError::ForwardDeclaredTyParam => { + ResolutionError::ForwardDeclaredGenericParam => { let mut err = struct_span_err!( self.session, span, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ffa825b7d46..408d9b23921 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -1763,13 +1763,33 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // to something unusable as a pattern (e.g., constructor function), // but we still conservatively report an error, see // issues/33118#issuecomment-233962221 for one reason why. + let binding = binding.expect("no binding for a ctor or static"); self.report_error( ident.span, - ResolutionError::BindingShadowsSomethingUnacceptable( - pat_src.descr(), - ident.name, - binding.expect("no binding for a ctor or static"), - ), + ResolutionError::BindingShadowsSomethingUnacceptable { + shadowing_binding_descr: pat_src.descr(), + name: ident.name, + participle: if binding.is_import() { "imported" } else { "defined" }, + article: binding.res().article(), + shadowed_binding_descr: binding.res().descr(), + shadowed_binding_span: binding.span, + }, + ); + None + } + Res::Def(DefKind::ConstParam, def_id) => { + // Same as for DefKind::Const above, but here, `binding` is `None`, so we + // have to construct the error differently + self.report_error( + ident.span, + ResolutionError::BindingShadowsSomethingUnacceptable { + shadowing_binding_descr: pat_src.descr(), + name: ident.name, + participle: "defined", + article: res.article(), + shadowed_binding_descr: res.descr(), + shadowed_binding_span: self.r.opt_span(def_id).expect("const parameter defined outside of local crate"), + } ); None } @@ -1939,7 +1959,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if ns == ValueNS { let item_name = path.last().unwrap().ident; let traits = self.traits_in_scope(item_name, ns); - self.r.trait_map.insert(id, traits); + self.r.trait_map.as_mut().unwrap().insert(id, traits); } if PrimTy::from_name(path[0].ident.name).is_some() { @@ -2415,12 +2435,12 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // the field name so that we can do some nice error reporting // later on in typeck. let traits = self.traits_in_scope(ident, ValueNS); - self.r.trait_map.insert(expr.id, traits); + self.r.trait_map.as_mut().unwrap().insert(expr.id, traits); } ExprKind::MethodCall(ref segment, ..) => { debug!("(recording candidate traits for expr) recording traits for {}", expr.id); let traits = self.traits_in_scope(segment.ident, ValueNS); - self.r.trait_map.insert(expr.id, traits); + self.r.trait_map.as_mut().unwrap().insert(expr.id, traits); } _ => { // Nothing to do. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 300d2c01cb5..41935e7d6df 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -16,7 +16,6 @@ #![feature(format_args_capture)] #![feature(iter_zip)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![recursion_limit = "256"] #![allow(rustdoc::private_intra_doc_links)] @@ -234,9 +233,16 @@ enum ResolutionError<'a> { /* current */ &'static str, ), /// Error E0530: `X` bindings cannot shadow `Y`s. - BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>), + BindingShadowsSomethingUnacceptable { + shadowing_binding_descr: &'static str, + name: Symbol, + participle: &'static str, + article: &'static str, + shadowed_binding_descr: &'static str, + shadowed_binding_span: Span, + }, /// Error E0128: generic parameters with a default cannot use forward-declared identifiers. - ForwardDeclaredTyParam, // FIXME(const_generics_defaults) + ForwardDeclaredGenericParam, /// ERROR E0770: the type of const parameters must not depend on other generic parameters. ParamInTyOfConstParam(Symbol), /// generic parameters must not be used inside const evaluations. @@ -903,7 +909,7 @@ pub struct Resolver<'a> { /// `CrateNum` resolutions of `extern crate` items. extern_crate_map: FxHashMap<LocalDefId, CrateNum>, export_map: ExportMap<LocalDefId>, - trait_map: NodeMap<Vec<TraitCandidate>>, + trait_map: Option<NodeMap<Vec<TraitCandidate>>>, /// A map from nodes to anonymous modules. /// Anonymous modules are pseudo-modules that are implicitly created around items @@ -1132,8 +1138,8 @@ impl ResolverAstLowering for Resolver<'_> { self.next_node_id() } - fn trait_map(&self) -> &NodeMap<Vec<TraitCandidate>> { - &self.trait_map + fn take_trait_map(&mut self) -> NodeMap<Vec<TraitCandidate>> { + std::mem::replace(&mut self.trait_map, None).unwrap() } fn opt_local_def_id(&self, node: NodeId) -> Option<LocalDefId> { @@ -1216,7 +1222,7 @@ impl<'a> Resolver<'a> { let mut module_map = FxHashMap::default(); module_map.insert(root_local_def_id, graph_root); - let definitions = Definitions::new(crate_name, session.local_crate_disambiguator()); + let definitions = Definitions::new(session.local_stable_crate_id()); let root = definitions.get_root_def(); let mut visibilities = FxHashMap::default(); @@ -1280,7 +1286,7 @@ impl<'a> Resolver<'a> { label_res_map: Default::default(), extern_crate_map: Default::default(), export_map: FxHashMap::default(), - trait_map: Default::default(), + trait_map: Some(NodeMap::default()), underscore_disambiguator: 0, empty_module, module_map, @@ -2602,7 +2608,7 @@ impl<'a> Resolver<'a> { let res_error = if rib_ident.name == kw::SelfUpper { ResolutionError::SelfInTyParamDefault } else { - ResolutionError::ForwardDeclaredTyParam + ResolutionError::ForwardDeclaredGenericParam }; self.report_error(span, res_error); } diff --git a/compiler/rustc_save_analysis/src/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs index 54b6a121585..842f7f9deee 100644 --- a/compiler/rustc_save_analysis/src/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -142,12 +142,7 @@ impl<'tcx> DumpVisitor<'tcx> { let data = CratePreludeData { crate_id: GlobalCrateId { name: name.into(), - disambiguator: self - .tcx - .sess - .local_crate_disambiguator() - .to_fingerprint() - .as_value(), + disambiguator: (self.tcx.sess.local_stable_crate_id().to_u64(), 0), }, crate_root: crate_root.unwrap_or_else(|| "<no source>".to_owned()), external_crates: self.save_ctxt.get_external_crates(), diff --git a/compiler/rustc_save_analysis/src/lib.rs b/compiler/rustc_save_analysis/src/lib.rs index 6c308ad89db..bdffdd5311e 100644 --- a/compiler/rustc_save_analysis/src/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -1,6 +1,5 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![recursion_limit = "256"] mod dump_visitor; @@ -128,7 +127,10 @@ impl<'tcx> SaveContext<'tcx> { num: n.as_u32(), id: GlobalCrateId { name: self.tcx.crate_name(n).to_string(), - disambiguator: self.tcx.crate_disambiguator(n).to_fingerprint().as_value(), + disambiguator: ( + self.tcx.def_path_hash(n.as_def_id()).stable_crate_id().to_u64(), + 0, + ), }, }); } diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs index cf5a9118275..c79786a839f 100644 --- a/compiler/rustc_serialize/src/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -14,10 +14,7 @@ Core encoding and decoding interfaces. #![feature(nll)] #![feature(associated_type_bounds)] #![feature(min_specialization)] -#![feature(vec_spare_capacity)] #![feature(core_intrinsics)] -#![feature(maybe_uninit_array_assume_init)] -#![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_slice)] #![feature(new_uninit)] #![cfg_attr(test, feature(test))] diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index f517c483758..94d2acc0602 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -677,6 +677,7 @@ impl Default for Options { optimize: OptLevel::No, debuginfo: DebugInfo::None, lint_opts: Vec::new(), + force_warns: Vec::new(), lint_cap: None, describe_lints: false, output_types: OutputTypes(BTreeMap::new()), @@ -1092,6 +1093,13 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> { level", "LEVEL", ), + opt::multi_s( + "", + "force-warns", + "Specifiy lints that should warn even if \ + they are allowed somewhere else", + "LINT", + ), opt::multi_s("C", "codegen", "Set a codegen option", "OPT[=VALUE]"), opt::flag_s("V", "version", "Print version info and exit"), opt::flag_s("v", "verbose", "Use verbose output"), @@ -1156,7 +1164,8 @@ pub fn rustc_optgroups() -> Vec<RustcOptGroup> { pub fn get_cmd_lint_options( matches: &getopts::Matches, error_format: ErrorOutputType, -) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>) { + debugging_opts: &DebuggingOptions, +) -> (Vec<(String, lint::Level)>, bool, Option<lint::Level>, Vec<String>) { let mut lint_opts_with_position = vec![]; let mut describe_lints = false; @@ -1189,7 +1198,18 @@ pub fn get_cmd_lint_options( lint::Level::from_str(&cap) .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{}`", cap))) }); - (lint_opts, describe_lints, lint_cap) + + if !debugging_opts.unstable_options && matches.opt_present("force-warns") { + early_error( + error_format, + "the `-Z unstable-options` flag must also be passed to enable \ + the flag `--force-warns=lints`", + ); + } + + let force_warns = matches.opt_strs("force-warns"); + + (lint_opts, describe_lints, lint_cap, force_warns) } /// Parses the `--color` flag. @@ -1507,7 +1527,10 @@ fn collect_print_requests( prints } -fn parse_target_triple(matches: &getopts::Matches, error_format: ErrorOutputType) -> TargetTriple { +pub fn parse_target_triple( + matches: &getopts::Matches, + error_format: ErrorOutputType, +) -> TargetTriple { match matches.opt_str("target") { Some(target) if target.ends_with(".json") => { let path = Path::new(&target); @@ -1923,9 +1946,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let crate_types = parse_crate_types_from_list(unparsed_crate_types) .unwrap_or_else(|e| early_error(error_format, &e[..])); - let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); - let mut debugging_opts = DebuggingOptions::build(matches, error_format); + let (lint_opts, describe_lints, lint_cap, force_warns) = + get_cmd_lint_options(matches, error_format, &debugging_opts); + check_debug_option_stability(&debugging_opts, error_format, json_rendered); if !debugging_opts.unstable_options && json_unused_externs { @@ -2097,6 +2121,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { optimize: opt_level, debuginfo, lint_opts, + force_warns, lint_cap, describe_lints, output_types, @@ -2424,22 +2449,6 @@ crate mod dep_tracking { )+}; } - macro_rules! impl_dep_tracking_hash_for_sortable_vec_of { - ($($t:ty),+ $(,)?) => {$( - impl DepTrackingHash for Vec<$t> { - fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) { - let mut elems: Vec<&$t> = self.iter().collect(); - elems.sort(); - Hash::hash(&elems.len(), hasher); - for (index, elem) in elems.iter().enumerate() { - Hash::hash(&index, hasher); - DepTrackingHash::hash(*elem, hasher, error_format); - } - } - } - )+}; - } - impl_dep_tracking_hash_via_hash!( bool, usize, @@ -2488,16 +2497,6 @@ crate mod dep_tracking { TrimmedDefPaths, ); - impl_dep_tracking_hash_for_sortable_vec_of!( - String, - PathBuf, - (PathBuf, PathBuf), - CrateType, - NativeLib, - (String, lint::Level), - (String, u64) - ); - impl<T1, T2> DepTrackingHash for (T1, T2) where T1: DepTrackingHash, @@ -2527,6 +2526,16 @@ crate mod dep_tracking { } } + impl<T: DepTrackingHash> DepTrackingHash for Vec<T> { + fn hash(&self, hasher: &mut DefaultHasher, error_format: ErrorOutputType) { + Hash::hash(&self.len(), hasher); + for (index, elem) in self.iter().enumerate() { + Hash::hash(&index, hasher); + DepTrackingHash::hash(elem, hasher, error_format); + } + } + } + // This is a stable hash because BTreeMap is a sorted container crate fn stable_hash( sub_hashes: BTreeMap<&'static str, &dyn DepTrackingHash>, diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 7971f7ef9ef..8d00a9a959e 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,6 +1,5 @@ #![feature(crate_visibility_modifier)] #![feature(once_cell)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![recursion_limit = "256"] #[macro_use] diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index c9f95ed1224..58a53b3de6e 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -130,6 +130,7 @@ top_level_options!( debuginfo: DebugInfo [TRACKED], lint_opts: Vec<(String, lint::Level)> [TRACKED], lint_cap: Option<lint::Level> [TRACKED], + force_warns: Vec<String> [TRACKED], describe_lints: bool [UNTRACKED], output_types: OutputTypes [TRACKED], search_paths: Vec<SearchPath> [UNTRACKED], @@ -368,7 +369,7 @@ mod desc { pub const parse_target_feature: &str = parse_string; pub const parse_wasi_exec_model: &str = "either `command` or `reactor`"; pub const parse_split_debuginfo: &str = - "one of supported split-debuginfo modes (`off` or `dsymutil`)"; + "one of supported split-debuginfo modes (`off`, `packed`, or `unpacked`)"; } mod parse { diff --git a/compiler/rustc_session/src/output.rs b/compiler/rustc_session/src/output.rs index 777eea3f68d..cc1e4bb198a 100644 --- a/compiler/rustc_session/src/output.rs +++ b/compiler/rustc_session/src/output.rs @@ -127,6 +127,11 @@ pub fn filename_for_metadata( crate_name: &str, outputs: &OutputFilenames, ) -> PathBuf { + // If the command-line specified the path, use that directly. + if let Some(Some(out_filename)) = sess.opts.output_types.get(&OutputType::Metadata) { + return out_filename.clone(); + } + let libname = format!("{}{}", crate_name, sess.opts.cg.extra_filename); let out_filename = outputs diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 1348b02b878..47833dcda4f 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -22,7 +22,7 @@ use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticId, ErrorReported}; use rustc_lint_defs::FutureBreakage; -pub use rustc_span::crate_disambiguator::CrateDisambiguator; +pub use rustc_span::def_id::StableCrateId; use rustc_span::source_map::{FileLoader, MultiSpan, RealFileLoader, SourceMap, Span}; use rustc_span::{edition::Edition, RealFileName}; use rustc_span::{sym, SourceFileHashAlgorithm, Symbol}; @@ -133,12 +133,12 @@ pub struct Session { /// in order to avoid redundantly verbose output (Issue #24690, #44953). pub one_time_diagnostics: Lock<FxHashSet<(DiagnosticMessageId, Option<Span>, String)>>, crate_types: OnceCell<Vec<CrateType>>, - /// The `crate_disambiguator` is constructed out of all the `-C metadata` - /// arguments passed to the compiler. Its value together with the crate-name - /// forms a unique global identifier for the crate. It is used to allow - /// multiple crates with the same name to coexist. See the + /// The `stable_crate_id` is constructed out of the crate name and all the + /// `-C metadata` arguments passed to the compiler. Its value forms a unique + /// global identifier for the crate. It is used to allow multiple crates + /// with the same name to coexist. See the /// `rustc_codegen_llvm::back::symbol_names` module for more information. - pub crate_disambiguator: OnceCell<CrateDisambiguator>, + pub stable_crate_id: OnceCell<StableCrateId>, features: OnceCell<rustc_feature::Features>, @@ -335,8 +335,8 @@ impl Session { self.parse_sess.span_diagnostic.emit_future_breakage_report(diags_and_breakage); } - pub fn local_crate_disambiguator(&self) -> CrateDisambiguator { - self.crate_disambiguator.get().copied().unwrap() + pub fn local_stable_crate_id(&self) -> StableCrateId { + self.stable_crate_id.get().copied().unwrap() } pub fn crate_types(&self) -> &[CrateType] { @@ -452,6 +452,7 @@ impl Session { pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) { err.into_diagnostic(self).emit() } + #[inline] pub fn err_count(&self) -> usize { self.diagnostic().err_count() } @@ -524,6 +525,7 @@ impl Session { self.diagnostic().struct_note_without_error(msg) } + #[inline] pub fn diagnostic(&self) -> &rustc_errors::Handler { &self.parse_sess.span_diagnostic } @@ -831,12 +833,12 @@ impl Session { /// Returns the symbol name for the registrar function, /// given the crate `Svh` and the function `DefIndex`. - pub fn generate_plugin_registrar_symbol(&self, disambiguator: CrateDisambiguator) -> String { - format!("__rustc_plugin_registrar_{}__", disambiguator.to_fingerprint().to_hex()) + pub fn generate_plugin_registrar_symbol(&self, stable_crate_id: StableCrateId) -> String { + format!("__rustc_plugin_registrar_{:08x}__", stable_crate_id.to_u64()) } - pub fn generate_proc_macro_decls_symbol(&self, disambiguator: CrateDisambiguator) -> String { - format!("__rustc_proc_macro_decls_{}__", disambiguator.to_fingerprint().to_hex()) + pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String { + format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.to_u64()) } pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> { @@ -1395,7 +1397,7 @@ pub fn build_session( working_dir, one_time_diagnostics: Default::default(), crate_types: OnceCell::new(), - crate_disambiguator: OnceCell::new(), + stable_crate_id: OnceCell::new(), features: OnceCell::new(), lint_store: OnceCell::new(), recursion_limit: OnceCell::new(), @@ -1512,6 +1514,14 @@ fn validate_commandline_args_with_session_available(sess: &Session) { if let (Some(first), Some(second)) = (sanitizer_iter.next(), sanitizer_iter.next()) { sess.err(&format!("`-Zsanitizer={}` is incompatible with `-Zsanitizer={}`", first, second)); } + + // Cannot enable crt-static with sanitizers on Linux + if sess.crt_static(None) && !sess.opts.debugging_opts.sanitizer.is_empty() { + sess.err( + "Sanitizer is incompatible with statically linked libc, \ + disable it using `-C target-feature=-crt-static`", + ); + } } /// Holds data on the current incremental compilation session, if there is one. diff --git a/compiler/rustc_span/src/crate_disambiguator.rs b/compiler/rustc_span/src/crate_disambiguator.rs deleted file mode 100644 index bd7d8516714..00000000000 --- a/compiler/rustc_span/src/crate_disambiguator.rs +++ /dev/null @@ -1,35 +0,0 @@ -// This is here because `rustc_session` wants to refer to it, -// and so does `rustc_hir`, but `rustc_hir` shouldn't refer to `rustc_session`. - -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::{base_n, impl_stable_hash_via_hash}; - -use std::fmt; - -/// Hash value constructed out of all the `-C metadata` arguments passed to the -/// compiler. Together with the crate-name forms a unique global identifier for -/// the crate. -#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy, Encodable, Decodable)] -pub struct CrateDisambiguator(Fingerprint); - -impl CrateDisambiguator { - pub fn to_fingerprint(self) -> Fingerprint { - self.0 - } -} - -impl fmt::Display for CrateDisambiguator { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - let (a, b) = self.0.as_value(); - let as_u128 = a as u128 | ((b as u128) << 64); - f.write_str(&base_n::encode(as_u128, base_n::CASE_INSENSITIVE)) - } -} - -impl From<Fingerprint> for CrateDisambiguator { - fn from(fingerprint: Fingerprint) -> CrateDisambiguator { - CrateDisambiguator(fingerprint) - } -} - -impl_stable_hash_via_hash!(CrateDisambiguator); diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 95bb0ad7ba2..b04a10d22a0 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -1,4 +1,3 @@ -use crate::crate_disambiguator::CrateDisambiguator; use crate::HashStableContext; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -10,65 +9,23 @@ use std::borrow::Borrow; use std::fmt; rustc_index::newtype_index! { - pub struct CrateId { + pub struct CrateNum { ENCODABLE = custom + DEBUG_FORMAT = "crate{}" } } -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub enum CrateNum { - /// A special `CrateNum` that we use for the `tcx.rcache` when decoding from - /// the incr. comp. cache. - ReservedForIncrCompCache, - Index(CrateId), -} - /// Item definitions in the currently-compiled crate would have the `CrateNum` /// `LOCAL_CRATE` in their `DefId`. -pub const LOCAL_CRATE: CrateNum = CrateNum::Index(CrateId::from_u32(0)); - -impl Idx for CrateNum { - #[inline] - fn new(value: usize) -> Self { - CrateNum::Index(Idx::new(value)) - } - - #[inline] - fn index(self) -> usize { - match self { - CrateNum::Index(idx) => Idx::index(idx), - _ => panic!("Tried to get crate index of {:?}", self), - } - } -} +pub const LOCAL_CRATE: CrateNum = CrateNum::from_u32(0); impl CrateNum { + #[inline] pub fn new(x: usize) -> CrateNum { CrateNum::from_usize(x) } - pub fn from_usize(x: usize) -> CrateNum { - CrateNum::Index(CrateId::from_usize(x)) - } - - pub fn from_u32(x: u32) -> CrateNum { - CrateNum::Index(CrateId::from_u32(x)) - } - - pub fn as_usize(self) -> usize { - match self { - CrateNum::Index(id) => id.as_usize(), - _ => panic!("tried to get index of non-standard crate {:?}", self), - } - } - - pub fn as_u32(self) -> u32 { - match self { - CrateNum::Index(id) => id.as_u32(), - _ => panic!("tried to get index of non-standard crate {:?}", self), - } - } - + #[inline] pub fn as_def_id(&self) -> DefId { DefId { krate: *self, index: CRATE_DEF_INDEX } } @@ -76,10 +33,7 @@ impl CrateNum { impl fmt::Display for CrateNum { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - CrateNum::Index(id) => fmt::Display::fmt(&id.private, f), - CrateNum::ReservedForIncrCompCache => write!(f, "crate for decoding incr comp cache"), - } + fmt::Display::fmt(&self.private, f) } } @@ -97,15 +51,6 @@ impl<D: Decoder> Decodable<D> for CrateNum { } } -impl ::std::fmt::Debug for CrateNum { - fn fmt(&self, fmt: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { - match self { - CrateNum::Index(id) => write!(fmt, "crate{}", id.private), - CrateNum::ReservedForIncrCompCache => write!(fmt, "crate for decoding incr comp cache"), - } - } -} - /// A `DefPathHash` is a fixed-size representation of a `DefPath` that is /// stable across crate and compilation session boundaries. It consists of two /// separate 64-bit hashes. The first uniquely identifies the crate this @@ -181,26 +126,51 @@ impl Borrow<Fingerprint> for DefPathHash { } } -/// A [StableCrateId] is a 64 bit hash of `(crate-name, crate-disambiguator)`. It -/// is to [CrateNum] what [DefPathHash] is to [DefId]. It is stable across -/// compilation sessions. +/// A [StableCrateId] is a 64 bit hash of the crate name combined with all +/// `-Cmetadata` arguments. It is to [CrateNum] what [DefPathHash] is to +/// [DefId]. It is stable across compilation sessions. /// /// Since the ID is a hash value there is a (very small) chance that two crates /// end up with the same [StableCrateId]. The compiler will check for such /// collisions when loading crates and abort compilation in order to avoid /// further trouble. -#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Encodable, Decodable)] +#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[derive(HashStable_Generic, Encodable, Decodable)] pub struct StableCrateId(u64); impl StableCrateId { + pub fn to_u64(self) -> u64 { + self.0 + } + /// Computes the stable ID for a crate with the given name and - /// disambiguator. - pub fn new(crate_name: &str, crate_disambiguator: CrateDisambiguator) -> StableCrateId { + /// `-Cmetadata` arguments. + pub fn new(crate_name: &str, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId { use std::hash::Hash; + use std::hash::Hasher; let mut hasher = StableHasher::new(); crate_name.hash(&mut hasher); - crate_disambiguator.hash(&mut hasher); + + // We don't want the stable crate id to dependent on the order + // -C metadata arguments, so sort them: + metadata.sort(); + // Every distinct -C metadata value is only incorporated once: + metadata.dedup(); + + hasher.write(b"metadata"); + for s in &metadata { + // Also incorporate the length of a metadata string, so that we generate + // different values for `-Cmetadata=ab -Cmetadata=c` and + // `-Cmetadata=a -Cmetadata=bc` + hasher.write_usize(s.len()); + hasher.write(s.as_bytes()); + } + + // Also incorporate crate type, so that we don't get symbol conflicts when + // linking against a library of the same name, if this is an executable. + hasher.write(if is_exe { b"exe" } else { b"lib" }); + StableCrateId(hasher.finish()) } } diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 0301b364591..51a53918f07 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -16,7 +16,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] #![feature(crate_visibility_modifier)] -#![feature(const_panic)] #![feature(negative_impls)] #![feature(nll)] #![feature(min_specialization)] @@ -46,8 +45,6 @@ pub mod lev_distance; mod span_encoding; pub use span_encoding::{Span, DUMMY_SP}; -pub mod crate_disambiguator; - pub mod symbol; pub use symbol::{sym, Symbol}; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 03a8f2be156..46ef308cbf2 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -130,10 +130,13 @@ symbols! { BTreeSet, BinaryHeap, Borrow, + Break, C, + CStr, CString, Center, Clone, + Continue, Copy, Count, Debug, @@ -326,6 +329,7 @@ symbols! { box_patterns, box_syntax, braced_empty_structs, + branch, breakpoint, bridge, bswap, @@ -411,6 +415,7 @@ symbols! { constructor, contents, context, + control_flow_enum, convert, copy, copy_closures, @@ -511,7 +516,6 @@ symbols! { env, eq, ermsb_target_feature, - err, exact_div, except, exchange_malloc, @@ -581,10 +585,10 @@ symbols! { frem_fast, from, from_desugaring, - from_error, from_generator, from_method, - from_ok, + from_output, + from_residual, from_size_align_unchecked, from_trait, from_usize, @@ -653,7 +657,6 @@ symbols! { instruction_set, intel, into_iter, - into_result, into_trait, intra_doc_pointers, intrinsics, @@ -965,6 +968,7 @@ symbols! { repr_packed, repr_simd, repr_transparent, + residual, result, result_type, rhs, @@ -1232,7 +1236,7 @@ symbols! { try_blocks, try_from_trait, try_into_trait, - try_trait, + try_trait_v2, tt, tuple, tuple_from_req, diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs index 7d186c330ba..0c64fe6ea60 100644 --- a/compiler/rustc_symbol_mangling/src/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -126,10 +126,9 @@ fn get_symbol_hash<'tcx>( substs.hash_stable(&mut hcx, &mut hasher); if let Some(instantiating_crate) = instantiating_crate { - tcx.original_crate_name(instantiating_crate) - .as_str() + tcx.def_path_hash(instantiating_crate.as_def_id()) + .stable_crate_id() .hash_stable(&mut hcx, &mut hasher); - tcx.crate_disambiguator(instantiating_crate).hash_stable(&mut hcx, &mut hasher); } // We want to avoid accidental collision between different types of instances. @@ -255,7 +254,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { } fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { - self.write_str(&self.tcx.original_crate_name(cnum).as_str())?; + self.write_str(&self.tcx.crate_name(cnum).as_str())?; Ok(self) } fn path_qualified( diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 7fb24ad1ed8..ba59ff96f65 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -90,7 +90,6 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(never_type)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(in_band_lifetimes)] #![recursion_limit = "256"] @@ -166,12 +165,12 @@ fn compute_symbol_name( // FIXME(eddyb) Precompute a custom symbol name based on attributes. let is_foreign = if let Some(def_id) = def_id.as_local() { if tcx.plugin_registrar_fn(()) == Some(def_id) { - let disambiguator = tcx.sess.local_crate_disambiguator(); - return tcx.sess.generate_plugin_registrar_symbol(disambiguator); + let stable_crate_id = tcx.sess.local_stable_crate_id(); + return tcx.sess.generate_plugin_registrar_symbol(stable_crate_id); } if tcx.proc_macro_decls_static(()) == Some(def_id) { - let disambiguator = tcx.sess.local_crate_disambiguator(); - return tcx.sess.generate_proc_macro_decls_symbol(disambiguator); + let stable_crate_id = tcx.sess.local_stable_crate_id(); + return tcx.sess.generate_proc_macro_decls_symbol(stable_crate_id); } let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); matches!(tcx.hir().get(hir_id), Node::ForeignItem(_)) diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 37a834043f6..e7da56ed0f3 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -485,9 +485,39 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { mut self, predicates: &'tcx ty::List<ty::Binder<'tcx, ty::ExistentialPredicate<'tcx>>>, ) -> Result<Self::DynExistential, Self::Error> { - for predicate in predicates { - self = self.in_binder(&predicate, |mut cx, predicate| { - match predicate { + // Okay, so this is a bit tricky. Imagine we have a trait object like + // `dyn for<'a> Foo<'a, Bar = &'a ()>`. When we mangle this, the + // output looks really close to the syntax, where the `Bar = &'a ()` bit + // is under the same binders (`['a]`) as the `Foo<'a>` bit. However, we + // actually desugar these into two separate `ExistentialPredicate`s. We + // can't enter/exit the "binder scope" twice though, because then we + // would mangle the binders twice. (Also, side note, we merging these + // two is kind of difficult, because of potential HRTBs in the Projection + // predicate.) + // + // Also worth mentioning: imagine that we instead had + // `dyn for<'a> Foo<'a, Bar = &'a ()> + Send`. In this case, `Send` is + // under the same binders as `Foo`. Currently, this doesn't matter, + // because only *auto traits* are allowed other than the principal trait + // and all auto traits don't have any generics. Two things could + // make this not an "okay" mangling: + // 1) Instead of mangling only *used* + // bound vars, we want to mangle *all* bound vars (`for<'b> Send` is a + // valid trait predicate); + // 2) We allow multiple "principal" traits in the future, or at least + // allow in any form another trait predicate that can take generics. + // + // Here we assume that predicates have the following structure: + // [<Trait> [{<Projection>}]] [{<Auto>}] + // Since any predicates after the first one shouldn't change the binders, + // just put them all in the binders of the first. + self = self.in_binder(&predicates[0], |mut cx, _| { + for predicate in predicates.iter() { + // It would be nice to be able to validate bound vars here, but + // projections can actually include bound vars from super traits + // because of HRTBs (only in the `Self` type). Also, auto traits + // could have different bound vars *anyways*. + match predicate.as_ref().skip_binder() { ty::ExistentialPredicate::Trait(trait_ref) => { // Use a type that can't appear in defaults of type parameters. let dummy_self = cx.tcx.mk_ty_infer(ty::FreshTy(0)); @@ -504,9 +534,10 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { cx = cx.print_def_path(*def_id, &[])?; } } - Ok(cx) - })?; - } + } + Ok(cx) + })?; + self.push("E"); Ok(self) } @@ -561,9 +592,9 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { fn path_crate(mut self, cnum: CrateNum) -> Result<Self::Path, Self::Error> { self.push("C"); - let fingerprint = self.tcx.crate_disambiguator(cnum).to_fingerprint(); - self.push_disambiguator(fingerprint.to_smaller_hash()); - let name = self.tcx.original_crate_name(cnum).as_str(); + let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id(); + self.push_disambiguator(stable_crate_id.to_u64()); + let name = self.tcx.crate_name(cnum).as_str(); self.push_ident(&name); Ok(self) } diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs index e2618da749f..1679d029374 100644 --- a/compiler/rustc_target/src/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -222,6 +222,7 @@ pub trait HasDataLayout { } impl HasDataLayout for TargetDataLayout { + #[inline] fn data_layout(&self) -> &TargetDataLayout { self } @@ -441,6 +442,8 @@ pub struct Align { } impl Align { + pub const ONE: Align = Align { pow2: 0 }; + #[inline] pub fn from_bits(bits: u64) -> Result<Align, String> { Align::from_bytes(Size::from_bits(bits).bytes()) @@ -450,7 +453,7 @@ impl Align { pub fn from_bytes(align: u64) -> Result<Align, String> { // Treat an alignment of 0 bytes like 1-byte alignment. if align == 0 { - return Ok(Align { pow2: 0 }); + return Ok(Align::ONE); } #[cold] @@ -860,6 +863,7 @@ pub enum Abi { impl Abi { /// Returns `true` if the layout corresponds to an unsized type. + #[inline] pub fn is_unsized(&self) -> bool { match *self { Abi::Uninhabited | Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } => false, @@ -879,11 +883,13 @@ impl Abi { } /// Returns `true` if this is an uninhabited type + #[inline] pub fn is_uninhabited(&self) -> bool { matches!(*self, Abi::Uninhabited) } /// Returns `true` is this is a scalar type + #[inline] pub fn is_scalar(&self) -> bool { matches!(*self, Abi::Scalar(_)) } diff --git a/compiler/rustc_target/src/lib.rs b/compiler/rustc_target/src/lib.rs index 48ace9b65b6..cb8f6b9656c 100644 --- a/compiler/rustc_target/src/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -9,11 +9,11 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] -#![feature(const_panic)] #![feature(nll)] #![feature(never_type)] #![feature(associated_type_bounds)] #![feature(exhaustive_patterns)] +#![feature(min_specialization)] use std::path::{Path, PathBuf}; diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs index 2218c6c6da7..5682039b865 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs @@ -10,7 +10,6 @@ pub fn target() -> Target { arch: "aarch64".to_string(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".to_string(), - eliminate_frame_pointer: false, max_atomic_width: Some(128), unsupported_abis: super::arm_base::unsupported_abis(), forces_embed_bitcode: true, diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs index 758950bd344..8a832546d09 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs @@ -10,7 +10,6 @@ pub fn target() -> Target { arch: "aarch64".to_string(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a12".to_string(), - eliminate_frame_pointer: false, max_atomic_width: Some(128), unsupported_abis: super::arm_base::unsupported_abis(), forces_embed_bitcode: true, diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs index e594ceec1b7..2187015b627 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_sim.rs @@ -18,7 +18,6 @@ pub fn target() -> Target { arch: "aarch64".to_string(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".to_string(), - eliminate_frame_pointer: false, max_atomic_width: Some(128), unsupported_abis: super::arm_base::unsupported_abis(), forces_embed_bitcode: true, diff --git a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs index a83de77dc2a..cb6c06b3711 100644 --- a/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs @@ -10,7 +10,6 @@ pub fn target() -> Target { arch: "aarch64".to_string(), options: TargetOptions { features: "+neon,+fp-armv8,+apple-a7".to_string(), - eliminate_frame_pointer: false, max_atomic_width: Some(128), unsupported_abis: super::arm_base::unsupported_abis(), forces_embed_bitcode: true, diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs index c9f622820de..de92b167f00 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs @@ -16,7 +16,6 @@ pub fn target() -> Target { executables: true, relocation_model: RelocModel::Static, disable_redzone: true, - linker_is_gnu: true, max_atomic_width: Some(128), panic_strategy: PanicStrategy::Abort, unsupported_abis: super::arm_base::unsupported_abis(), diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs index 0811871c993..2566eeae14a 100644 --- a/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs @@ -16,7 +16,6 @@ pub fn target() -> Target { executables: true, relocation_model: RelocModel::Static, disable_redzone: true, - linker_is_gnu: true, max_atomic_width: Some(128), panic_strategy: PanicStrategy::Abort, unsupported_abis: super::arm_base::unsupported_abis(), diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs index bc2ec670901..8530db179d9 100644 --- a/compiler/rustc_target/src/spec/apple_base.rs +++ b/compiler/rustc_target/src/spec/apple_base.rs @@ -22,10 +22,12 @@ pub fn opts(os: &str) -> TargetOptions { // macOS has -dead_strip, which doesn't rely on function_sections function_sections: false, dynamic_linking: true, + linker_is_gnu: false, executables: true, families: vec!["unix".to_string()], is_like_osx: true, dwarf_version: Some(2), + eliminate_frame_pointer: false, has_rpath: true, dll_suffix: ".dylib".to_string(), archive_format: "darwin".to_string(), diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs index 538c4ca8697..e7f7bb343d0 100644 --- a/compiler/rustc_target/src/spec/apple_sdk_base.rs +++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs @@ -44,7 +44,6 @@ pub fn opts(os: &str, arch: Arch) -> TargetOptions { executables: true, link_env_remove: link_env_remove(arch), has_elf_tls: false, - eliminate_frame_pointer: false, ..super::apple_base::opts(os) } } diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs index 69ccce875ab..2cb2661a526 100644 --- a/compiler/rustc_target/src/spec/avr_gnu_base.rs +++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs @@ -16,7 +16,6 @@ pub fn target(target_cpu: String) -> Target { linker: Some("avr-gcc".to_owned()), executables: true, - linker_is_gnu: true, eh_frame_header: false, pre_link_args: vec![(LinkerFlavor::Gcc, vec![format!("-mmcu={}", target_cpu)])] .into_iter() diff --git a/compiler/rustc_target/src/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs index fb94498c131..e13a640d4d2 100644 --- a/compiler/rustc_target/src/spec/dragonfly_base.rs +++ b/compiler/rustc_target/src/spec/dragonfly_base.rs @@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, has_rpath: true, position_independent_executables: true, relro_level: RelroLevel::Full, diff --git a/compiler/rustc_target/src/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs index 5d3c28e5f29..bef2fce7c83 100644 --- a/compiler/rustc_target/src/spec/freebsd_base.rs +++ b/compiler/rustc_target/src/spec/freebsd_base.rs @@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, has_rpath: true, position_independent_executables: true, eliminate_frame_pointer: false, // FIXME 43575 diff --git a/compiler/rustc_target/src/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs index 13264dffeb4..23a2e65749e 100644 --- a/compiler/rustc_target/src/spec/fuchsia_base.rs +++ b/compiler/rustc_target/src/spec/fuchsia_base.rs @@ -27,7 +27,6 @@ pub fn opts() -> TargetOptions { executables: true, families: vec!["unix".to_string()], is_like_fuchsia: true, - linker_is_gnu: true, pre_link_args, pre_link_objects: crt_objects::new(&[ (LinkOutputKind::DynamicNoPicExe, &["Scrt1.o"]), diff --git a/compiler/rustc_target/src/spec/haiku_base.rs b/compiler/rustc_target/src/spec/haiku_base.rs index fae56f6a82d..2b95523d6f7 100644 --- a/compiler/rustc_target/src/spec/haiku_base.rs +++ b/compiler/rustc_target/src/spec/haiku_base.rs @@ -7,7 +7,6 @@ pub fn opts() -> TargetOptions { executables: true, families: vec!["unix".to_string()], relro_level: RelroLevel::Full, - linker_is_gnu: true, ..Default::default() } } diff --git a/compiler/rustc_target/src/spec/hermit_base.rs b/compiler/rustc_target/src/spec/hermit_base.rs index ad013047e6a..75ca1f79b12 100644 --- a/compiler/rustc_target/src/spec/hermit_base.rs +++ b/compiler/rustc_target/src/spec/hermit_base.rs @@ -13,7 +13,6 @@ pub fn opts() -> TargetOptions { linker: Some("rust-lld".to_owned()), executables: true, has_elf_tls: true, - linker_is_gnu: true, pre_link_args, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/hermit_kernel_base.rs b/compiler/rustc_target/src/spec/hermit_kernel_base.rs index 6d18a14d6ae..c55a46e69a8 100644 --- a/compiler/rustc_target/src/spec/hermit_kernel_base.rs +++ b/compiler/rustc_target/src/spec/hermit_kernel_base.rs @@ -14,7 +14,6 @@ pub fn opts() -> TargetOptions { linker: Some("rust-lld".to_owned()), executables: true, has_elf_tls: true, - linker_is_gnu: true, pre_link_args, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs index 2b8e046c46b..9d9da50be7a 100644 --- a/compiler/rustc_target/src/spec/illumos_base.rs +++ b/compiler/rustc_target/src/spec/illumos_base.rs @@ -33,6 +33,7 @@ pub fn opts() -> TargetOptions { has_rpath: true, families: vec!["unix".to_string()], is_like_solaris: true, + linker_is_gnu: false, limit_rdylib_exports: false, // Linker doesn't support this eliminate_frame_pointer: false, eh_frame_header: false, diff --git a/compiler/rustc_target/src/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs index 65c343a5f21..f6e3102f617 100644 --- a/compiler/rustc_target/src/spec/l4re_base.rs +++ b/compiler/rustc_target/src/spec/l4re_base.rs @@ -20,6 +20,7 @@ pub fn opts() -> TargetOptions { executables: true, panic_strategy: PanicStrategy::Abort, linker: Some("ld".to_string()), + linker_is_gnu: false, families: vec!["unix".to_string()], ..Default::default() } diff --git a/compiler/rustc_target/src/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs index 184659e22d9..af81bc714c7 100644 --- a/compiler/rustc_target/src/spec/linux_base.rs +++ b/compiler/rustc_target/src/spec/linux_base.rs @@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, has_rpath: true, position_independent_executables: true, relro_level: RelroLevel::Full, diff --git a/compiler/rustc_target/src/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs index 64f47b4aa9b..145aa4a5894 100644 --- a/compiler/rustc_target/src/spec/linux_kernel_base.rs +++ b/compiler/rustc_target/src/spec/linux_kernel_base.rs @@ -8,7 +8,6 @@ pub fn opts() -> TargetOptions { // don't use probe-stack=inline-asm until rust#83139 and rust#84667 are resolved stack_probes: StackProbeType::Call, eliminate_frame_pointer: false, - linker_is_gnu: true, position_independent_executables: true, needs_plt: true, relro_level: RelroLevel::Full, diff --git a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs index 08c290e6ff1..dc14e4bdf94 100644 --- a/compiler/rustc_target/src/spec/mipsel_sony_psp.rs +++ b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs @@ -21,7 +21,6 @@ pub fn target() -> Target { cpu: "mips2".to_string(), executables: true, linker: Some("rust-lld".to_owned()), - linker_is_gnu: true, relocation_model: RelocModel::Static, // PSP FPU only supports single precision floats. diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs index 4bffd6e8ddd..4683def94f7 100644 --- a/compiler/rustc_target/src/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -922,6 +922,7 @@ pub trait HasTargetSpec { } impl HasTargetSpec for Target { + #[inline] fn target_spec(&self) -> &Target { self } @@ -1086,7 +1087,7 @@ pub struct TargetOptions { /// Version of DWARF to use if not using the default. /// Useful because some platforms (osx, bsd) only want up to DWARF2. pub dwarf_version: Option<u32>, - /// Whether the linker support GNU-like arguments such as -O. Defaults to false. + /// Whether the linker support GNU-like arguments such as -O. Defaults to true. pub linker_is_gnu: bool, /// The MinGW toolchain has a known issue that prevents it from correctly /// handling COFF object files with more than 2<sup>15</sup> sections. Since each weak @@ -1307,7 +1308,7 @@ impl Default for TargetOptions { is_like_fuchsia: false, is_like_wasm: false, dwarf_version: None, - linker_is_gnu: false, + linker_is_gnu: true, allows_weak_linkage: true, has_rpath: false, no_default_libraries: true, diff --git a/compiler/rustc_target/src/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs index 4ed7685ca07..f1ed4c154d2 100644 --- a/compiler/rustc_target/src/spec/msvc_base.rs +++ b/compiler/rustc_target/src/spec/msvc_base.rs @@ -16,6 +16,7 @@ pub fn opts() -> TargetOptions { is_like_windows: true, is_like_msvc: true, lld_flavor: LldFlavor::Link, + linker_is_gnu: false, pre_link_args, abi_return_struct_as_int: true, emit_debug_gdb_scripts: false, diff --git a/compiler/rustc_target/src/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs index 602fb6eb641..6bb6083d47c 100644 --- a/compiler/rustc_target/src/spec/netbsd_base.rs +++ b/compiler/rustc_target/src/spec/netbsd_base.rs @@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, no_default_libraries: false, has_rpath: true, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs index 15d8e4843f9..97960a75b09 100644 --- a/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs +++ b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs @@ -14,6 +14,7 @@ pub fn target() -> Target { linker_flavor: LinkerFlavor::PtxLinker, // The linker can be installed from `crates.io`. linker: Some("rust-ptx-linker".to_string()), + linker_is_gnu: false, // With `ptx-linker` approach, it can be later overridden via link flags. cpu: "sm_30".to_string(), diff --git a/compiler/rustc_target/src/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs index 8f33bacd922..29b415e7726 100644 --- a/compiler/rustc_target/src/spec/openbsd_base.rs +++ b/compiler/rustc_target/src/spec/openbsd_base.rs @@ -6,7 +6,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, has_rpath: true, abi_return_struct_as_int: true, position_independent_executables: true, diff --git a/compiler/rustc_target/src/spec/redox_base.rs b/compiler/rustc_target/src/spec/redox_base.rs index 72052b9e2e2..fcf5db3746d 100644 --- a/compiler/rustc_target/src/spec/redox_base.rs +++ b/compiler/rustc_target/src/spec/redox_base.rs @@ -7,7 +7,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, has_rpath: true, position_independent_executables: true, relro_level: RelroLevel::Full, diff --git a/compiler/rustc_target/src/spec/solaris_base.rs b/compiler/rustc_target/src/spec/solaris_base.rs index 4c922eb5cea..bc32b501688 100644 --- a/compiler/rustc_target/src/spec/solaris_base.rs +++ b/compiler/rustc_target/src/spec/solaris_base.rs @@ -8,6 +8,7 @@ pub fn opts() -> TargetOptions { has_rpath: true, families: vec!["unix".to_string()], is_like_solaris: true, + linker_is_gnu: false, limit_rdylib_exports: false, // Linker doesn't support this eh_frame_header: false, diff --git a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs index ef58824f381..f996009f830 100644 --- a/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs +++ b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs @@ -28,7 +28,6 @@ pub fn target() -> Target { options: TargetOptions { linker_flavor: LinkerFlavor::Ld, linker: Some("arm-none-eabi-ld".to_string()), - linker_is_gnu: true, // extra args passed to the external assembler (assuming `arm-none-eabi-as`): // * activate t32/a32 interworking diff --git a/compiler/rustc_target/src/spec/vxworks_base.rs b/compiler/rustc_target/src/spec/vxworks_base.rs index 0e8e87f2dff..a91e7717865 100644 --- a/compiler/rustc_target/src/spec/vxworks_base.rs +++ b/compiler/rustc_target/src/spec/vxworks_base.rs @@ -10,7 +10,6 @@ pub fn opts() -> TargetOptions { dynamic_linking: true, executables: true, families: vec!["unix".to_string()], - linker_is_gnu: true, has_rpath: true, has_elf_tls: true, crt_static_default: true, diff --git a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs index ddf28b423f0..302139395d3 100644 --- a/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs +++ b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs @@ -34,7 +34,6 @@ pub fn target() -> Target { // functionality, and a .wasm file. exe_suffix: ".js".to_string(), linker: None, - linker_is_gnu: true, is_like_emscripten: true, panic_strategy: PanicStrategy::Unwind, post_link_args, diff --git a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs index 90705c526f4..06eb33d8d82 100644 --- a/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs +++ b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs @@ -57,7 +57,6 @@ pub fn target() -> Target { vendor: "fortanix".into(), linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), executables: true, - linker_is_gnu: true, linker: Some("rust-lld".to_owned()), max_atomic_width: Some(64), cpu: "x86-64".into(), diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs index 3f24a33f7d5..ac2e0ebae32 100644 --- a/compiler/rustc_trait_selection/src/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -6,6 +6,7 @@ use rustc_infer::infer::InferCtxt; use rustc_middle::ty::{self, TraitRef, Ty, TyCtxt, WithConstness}; use rustc_middle::ty::{ToPredicate, TypeFoldable}; use rustc_session::DiagnosticMessageId; +use rustc_span::def_id::LOCAL_CRATE; use rustc_span::Span; #[derive(Copy, Clone, Debug)] @@ -231,7 +232,8 @@ pub fn report_autoderef_recursion_limit_error<'tcx>(tcx: TyCtxt<'tcx>, span: Spa .span_label(span, "deref recursion limit reached") .help(&format!( "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", - suggested_limit, tcx.crate_name, + suggested_limit, + tcx.crate_name(LOCAL_CRATE), )) .emit(); } diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index bf3c8643f0d..e932b1bca7c 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -19,7 +19,6 @@ #![feature(iter_zip)] #![feature(never_type)] #![feature(crate_visibility_modifier)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(control_flow_enum)] #![recursion_limit = "512"] // For rustdoc diff --git a/compiler/rustc_trait_selection/src/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs index fb4a8ce687c..163df26e9ff 100644 --- a/compiler/rustc_trait_selection/src/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -46,6 +46,7 @@ pub struct OpaqueTypeDecl<'tcx> { /// type Foo = impl Baz; /// fn bar() -> Foo { /// // ^^^ This is the span we are looking for! + /// } /// ``` /// /// In cases where the fn returns `(impl Trait, impl Trait)` or @@ -139,15 +140,6 @@ pub trait InferCtxtExt<'tcx> { first_own_region_index: usize, ); - /*private*/ - fn member_constraint_feature_gate( - &self, - opaque_defn: &OpaqueTypeDecl<'tcx>, - opaque_type_def_id: DefId, - conflict1: ty::Region<'tcx>, - conflict2: ty::Region<'tcx>, - ) -> bool; - fn infer_opaque_definition_from_instantiation( &self, def_id: DefId, @@ -489,9 +481,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // ['a, 'b, 'c]`, where `'a..'c` are the // regions that appear in the impl trait. - // For now, enforce a feature gate outside of async functions. - self.member_constraint_feature_gate(opaque_defn, def_id, lr, subst_region); - return self.generate_member_constraint( concrete_ty, opaque_defn, @@ -558,60 +547,6 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }); } - /// Member constraints are presently feature-gated except for - /// async-await. We expect to lift this once we've had a bit more - /// time. - fn member_constraint_feature_gate( - &self, - opaque_defn: &OpaqueTypeDecl<'tcx>, - opaque_type_def_id: DefId, - conflict1: ty::Region<'tcx>, - conflict2: ty::Region<'tcx>, - ) -> bool { - // If we have `#![feature(member_constraints)]`, no problems. - if self.tcx.features().member_constraints { - return false; - } - - let span = self.tcx.def_span(opaque_type_def_id); - - // Without a feature-gate, we only generate member-constraints for async-await. - let context_name = match opaque_defn.origin { - // No feature-gate required for `async fn`. - hir::OpaqueTyOrigin::AsyncFn => return false, - - // Otherwise, generate the label we'll use in the error message. - hir::OpaqueTyOrigin::Binding - | hir::OpaqueTyOrigin::FnReturn - | hir::OpaqueTyOrigin::TyAlias - | hir::OpaqueTyOrigin::Misc => "impl Trait", - }; - let msg = format!("ambiguous lifetime bound in `{}`", context_name); - let mut err = self.tcx.sess.struct_span_err(span, &msg); - - let conflict1_name = conflict1.to_string(); - let conflict2_name = conflict2.to_string(); - let label_owned; - let label = match (&*conflict1_name, &*conflict2_name) { - ("'_", "'_") => "the elided lifetimes here do not outlive one another", - _ => { - label_owned = format!( - "neither `{}` nor `{}` outlives the other", - conflict1_name, conflict2_name, - ); - &label_owned - } - }; - err.span_label(span, label); - - if self.tcx.sess.is_nightly_build() { - err.help("add #![feature(member_constraints)] to the crate attributes to enable"); - } - - err.emit(); - true - } - /// Given the fully resolved, instantiated type for an opaque /// type, i.e., the value of an inference variable like C1 or C2 /// (*), computes the "definition type" for an opaque type diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 1ea34e5814e..0ca0245a203 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -186,6 +186,15 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; let name = param.name; flags.push((name, Some(value))); + + if let GenericParamDefKind::Type { .. } = param.kind { + let param_ty = trait_ref.substs[param.index as usize].expect_ty(); + if let Some(def) = param_ty.ty_adt_def() { + // We also want to be able to select the parameter's + // original signature with no type arguments resolved + flags.push((name, Some(self.tcx.type_of(def.did).to_string()))); + } + } } if let Some(true) = self_ty.ty_adt_def().map(|def| def.did.is_local()) { diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 6a4d41ffc1a..5c35b515f3d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -21,6 +21,7 @@ use rustc_middle::ty::{ Infer, InferTy, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, }; use rustc_middle::ty::{TypeAndMut, TypeckResults}; +use rustc_span::def_id::LOCAL_CRATE; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, MultiSpan, Span, DUMMY_SP}; use rustc_target::spec::abi; @@ -686,17 +687,36 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return false; } + // Blacklist traits for which it would be nonsensical to suggest borrowing. + // For instance, immutable references are always Copy, so suggesting to + // borrow would always succeed, but it's probably not what the user wanted. + let blacklist: Vec<_> = + [LangItem::Copy, LangItem::Clone, LangItem::Unpin, LangItem::Sized, LangItem::Send] + .iter() + .filter_map(|lang_item| self.tcx.lang_items().require(*lang_item).ok()) + .collect(); + let span = obligation.cause.span; let param_env = obligation.param_env; let trait_ref = trait_ref.skip_binder(); - if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code { - // Try to apply the original trait binding obligation by borrowing. - let self_ty = trait_ref.self_ty(); - let found = self_ty.to_string(); - let new_self_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, self_ty); - let substs = self.tcx.mk_substs_trait(new_self_ty, &[]); - let new_trait_ref = ty::TraitRef::new(obligation.parent_trait_ref.def_id(), substs); + let found_ty = trait_ref.self_ty(); + let found_ty_str = found_ty.to_string(); + let imm_borrowed_found_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_static, found_ty); + let imm_substs = self.tcx.mk_substs_trait(imm_borrowed_found_ty, &[]); + let mut_borrowed_found_ty = self.tcx.mk_mut_ref(self.tcx.lifetimes.re_static, found_ty); + let mut_substs = self.tcx.mk_substs_trait(mut_borrowed_found_ty, &[]); + + // Try to apply the original trait binding obligation by borrowing. + let mut try_borrowing = |new_trait_ref: ty::TraitRef<'tcx>, + expected_trait_ref: ty::TraitRef<'tcx>, + mtbl: bool, + blacklist: &[DefId]| + -> bool { + if blacklist.contains(&expected_trait_ref.def_id) { + return false; + } + let new_obligation = Obligation::new( ObligationCause::dummy(), param_env, @@ -713,8 +733,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let msg = format!( "the trait bound `{}: {}` is not satisfied", - found, - obligation.parent_trait_ref.skip_binder().print_only_trait_path(), + found_ty_str, + expected_trait_ref.print_only_trait_path(), ); if has_custom_message { err.note(&msg); @@ -730,7 +750,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { span, &format!( "expected an implementor of trait `{}`", - obligation.parent_trait_ref.skip_binder().print_only_trait_path(), + expected_trait_ref.print_only_trait_path(), ), ); @@ -745,16 +765,52 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { err.span_suggestion( span, - "consider borrowing here", - format!("&{}", snippet), + &format!( + "consider{} borrowing here", + if mtbl { " mutably" } else { "" } + ), + format!("&{}{}", if mtbl { "mut " } else { "" }, snippet), Applicability::MaybeIncorrect, ); } return true; } } + return false; + }; + + if let ObligationCauseCode::ImplDerivedObligation(obligation) = &obligation.cause.code { + let expected_trait_ref = obligation.parent_trait_ref.skip_binder(); + let new_imm_trait_ref = + ty::TraitRef::new(obligation.parent_trait_ref.def_id(), imm_substs); + let new_mut_trait_ref = + ty::TraitRef::new(obligation.parent_trait_ref.def_id(), mut_substs); + if try_borrowing(new_imm_trait_ref, expected_trait_ref, false, &[]) { + return true; + } else { + return try_borrowing(new_mut_trait_ref, expected_trait_ref, true, &[]); + } + } else if let ObligationCauseCode::BindingObligation(_, _) + | ObligationCauseCode::ItemObligation(_) = &obligation.cause.code + { + if try_borrowing( + ty::TraitRef::new(trait_ref.def_id, imm_substs), + trait_ref, + false, + &blacklist[..], + ) { + return true; + } else { + return try_borrowing( + ty::TraitRef::new(trait_ref.def_id, mut_substs), + trait_ref, + true, + &blacklist[..], + ); + } + } else { + false } - false } /// Whenever references are used by mistake, like `for (i, e) in &vec.iter().enumerate()`, @@ -2258,7 +2314,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let suggested_limit = current_limit * 2; err.help(&format!( "consider adding a `#![recursion_limit=\"{}\"]` attribute to your crate (`{}`)", - suggested_limit, self.tcx.crate_name, + suggested_limit, + self.tcx.crate_name(LOCAL_CRATE), )); } diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index fc9739f70d4..120680092ba 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -6,7 +6,7 @@ use rustc_errors::ErrorReported; use rustc_infer::traits::{SelectionError, TraitEngine, TraitEngineExt as _, TraitObligation}; use rustc_middle::mir::abstract_const::NotConstEvaluatable; use rustc_middle::mir::interpret::ErrorHandled; -use rustc_middle::ty::error::ExpectedFound; +use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable}; @@ -591,7 +591,16 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { ) } (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { - ProcessResult::Unchanged + if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() { + ProcessResult::Unchanged + } else { + // Two different constants using generic parameters ~> error. + let expected_found = ExpectedFound::new(true, c1, c2); + ProcessResult::Error(FulfillmentErrorCode::CodeConstEquateError( + expected_found, + TypeError::ConstMismatch(expected_found), + )) + } } } } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index b3e5df4da0a..388413ae06b 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -529,15 +529,7 @@ fn opt_normalize_projection_type<'a, 'b, 'tcx>( // evaluation this is not the case, and dropping the trait // evaluations can causes ICEs (e.g., #43132). debug!(?ty, "found normalized ty"); - - // Once we have inferred everything we need to know, we - // can ignore the `obligations` from that point on. - if infcx.unresolved_type_vars(&ty.value).is_none() { - infcx.inner.borrow_mut().projection_cache().complete_normalized(cache_key, &ty); - // No need to extend `obligations`. - } else { - obligations.extend(ty.obligations); - } + obligations.extend(ty.obligations); return Ok(Some(ty.value)); } Err(ProjectionCacheEntry::Error) => { diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index a292de148a6..ea5eb2b6866 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -557,6 +557,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ty::PredicateKind::ConstEquate(c1, c2) => { debug!(?c1, ?c2, "evaluate_predicate_recursively: equating consts"); + if self.tcx().features().const_evaluatable_checked { + // FIXME: we probably should only try to unify abstract constants + // if the constants depend on generic parameters. + // + // Let's just see where this breaks :shrug: + if let (ty::ConstKind::Unevaluated(a), ty::ConstKind::Unevaluated(b)) = + (c1.val, c2.val) + { + if self + .tcx() + .try_unify_abstract_consts(((a.def, a.substs), (b.def, b.substs))) + { + return Ok(EvaluatedToOk); + } + } + } + let evaluate = |c: &'tcx ty::Const<'tcx>| { if let ty::ConstKind::Unevaluated(unevaluated) = c.val { self.infcx @@ -591,7 +608,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ) } (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { - Ok(EvaluatedToAmbig) + if c1.has_infer_types_or_consts() || c2.has_infer_types_or_consts() { + Ok(EvaluatedToAmbig) + } else { + // Two different constants using generic parameters ~> error. + Ok(EvaluatedToErr) + } } } } diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 144c7281b67..07a3132568b 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -1,13 +1,11 @@ use rustc_data_structures::fx::FxIndexSet; use rustc_hir as hir; -use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::{ self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness, }; -use rustc_session::CrateDisambiguator; -use rustc_span::symbol::Symbol; use rustc_span::Span; use rustc_trait_selection::traits; @@ -389,16 +387,6 @@ fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamE tcx.param_env(def_id).with_reveal_all_normalized(tcx) } -fn crate_disambiguator(tcx: TyCtxt<'_>, crate_num: CrateNum) -> CrateDisambiguator { - assert_eq!(crate_num, LOCAL_CRATE); - tcx.sess.local_crate_disambiguator() -} - -fn original_crate_name(tcx: TyCtxt<'_>, crate_num: CrateNum) -> Symbol { - assert_eq!(crate_num, LOCAL_CRATE); - tcx.crate_name -} - fn instance_def_size_estimate<'tcx>( tcx: TyCtxt<'tcx>, instance_def: ty::InstanceDef<'tcx>, @@ -544,8 +532,6 @@ pub fn provide(providers: &mut ty::query::Providers) { param_env, param_env_reveal_all_normalized, trait_of_item, - crate_disambiguator, - original_crate_name, instance_def_size_estimate, issue33140_self_ty, impl_defaultness, diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index 0dbcd483c45..2d102127dd9 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -1,3 +1,5 @@ +#![feature(min_specialization)] + #[macro_use] extern crate bitflags; #[macro_use] diff --git a/compiler/rustc_typeck/src/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs index 5285c1c8598..ef195621044 100644 --- a/compiler/rustc_typeck/src/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -1394,11 +1394,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let auto_trait_predicates = auto_traits.into_iter().map(|trait_ref| { ty::Binder::dummy(ty::ExistentialPredicate::AutoTrait(trait_ref.trait_ref().def_id())) }); + // N.b. principal, projections, auto traits + // FIXME: This is actually wrong with multiple principals in regards to symbol mangling let mut v = regular_trait_predicates - .chain(auto_trait_predicates) .chain( existential_projections.map(|x| x.map_bound(ty::ExistentialPredicate::Projection)), ) + .chain(auto_trait_predicates) .collect::<SmallVec<[_; 8]>>(); v.sort_by(|a, b| a.skip_binder().stable_cmp(tcx, &b.skip_binder())); v.dedup(); diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index b760a54f08c..3cbc3d231f8 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -35,6 +35,7 @@ use crate::type_error_struct; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorReported}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; +use rustc_middle::mir::Mutability; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::cast::{CastKind, CastTy}; use rustc_middle::ty::error::TypeError; @@ -347,15 +348,52 @@ impl<'a, 'tcx> CastCheck<'tcx> { fcx.ty_to_string(self.cast_ty) ); let mut sugg = None; + let mut sugg_mutref = false; if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() { - if fcx - .try_coerce( - self.expr, - fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }), - self.cast_ty, - AllowTwoPhase::No, - ) - .is_ok() + if let ty::RawPtr(TypeAndMut { ty: expr_ty, .. }) = *self.expr_ty.kind() { + if fcx + .try_coerce( + self.expr, + fcx.tcx.mk_ref( + &ty::RegionKind::ReErased, + TypeAndMut { ty: expr_ty, mutbl }, + ), + self.cast_ty, + AllowTwoPhase::No, + ) + .is_ok() + { + sugg = Some(format!("&{}*", mutbl.prefix_str())); + } + } else if let ty::Ref(expr_reg, expr_ty, expr_mutbl) = *self.expr_ty.kind() { + if expr_mutbl == Mutability::Not + && mutbl == Mutability::Mut + && fcx + .try_coerce( + self.expr, + fcx.tcx.mk_ref( + expr_reg, + TypeAndMut { ty: expr_ty, mutbl: Mutability::Mut }, + ), + self.cast_ty, + AllowTwoPhase::No, + ) + .is_ok() + { + sugg_mutref = true; + } + } + + if !sugg_mutref + && sugg == None + && fcx + .try_coerce( + self.expr, + fcx.tcx.mk_ref(reg, TypeAndMut { ty: self.expr_ty, mutbl }), + self.cast_ty, + AllowTwoPhase::No, + ) + .is_ok() { sugg = Some(format!("&{}", mutbl.prefix_str())); } @@ -375,11 +413,15 @@ impl<'a, 'tcx> CastCheck<'tcx> { sugg = Some(format!("&{}", mutbl.prefix_str())); } } - if let Some(sugg) = sugg { + if sugg_mutref { + err.span_label(self.span, "invalid cast"); + err.span_note(self.expr.span, "this reference is immutable"); + err.span_note(self.cast_span, "trying to cast to a mutable reference type"); + } else if let Some(sugg) = sugg { err.span_label(self.span, "invalid cast"); err.span_suggestion_verbose( self.expr.span.shrink_to_lo(), - "borrow the value for the cast to be valid", + "consider borrowing the value", sugg, Applicability::MachineApplicable, ); diff --git a/compiler/rustc_typeck/src/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs index e5fcdcfa743..9cc435a0dec 100644 --- a/compiler/rustc_typeck/src/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -8,6 +8,7 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; use rustc_hir::{is_range_literal, Node}; +use rustc_middle::lint::in_external_macro; use rustc_middle::ty::adjustment::AllowTwoPhase; use rustc_middle::ty::{self, AssocItem, Ty, TypeAndMut}; use rustc_span::symbol::sym; @@ -412,14 +413,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { checked_ty: Ty<'tcx>, expected: Ty<'tcx>, ) -> Option<(Span, &'static str, String, Applicability)> { - let sm = self.sess().source_map(); + let sess = self.sess(); let sp = expr.span; - if sm.is_imported(sp) { - // Ignore if span is from within a macro #41858, #58298. We previously used the macro - // call span, but that breaks down when the type error comes from multiple calls down. + + // If the span is from an external macro, there's no suggestion we can make. + if in_external_macro(sess, sp) { return None; } + let sm = sess.source_map(); + let replace_prefix = |s: &str, old: &str, new: &str| { s.strip_prefix(old).map(|stripped| new.to_string() + stripped) }; @@ -427,10 +430,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let is_struct_pat_shorthand_field = self.is_hir_id_from_struct_pattern_shorthand_field(expr.hir_id, sp); - // If the span is from a macro, then it's hard to extract the text - // and make a good suggestion, so don't bother. - let is_macro = sp.from_expansion() && sp.desugaring_kind().is_none(); - // `ExprKind::DropTemps` is semantically irrelevant for these suggestions. let expr = expr.peel_drop_temps(); @@ -570,10 +569,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::ExprKind::AddrOf(hir::BorrowKind::Ref, _, ref expr), _, &ty::Ref(_, checked, _), - ) if { - self.infcx.can_sub(self.param_env, checked, &expected).is_ok() && !is_macro - } => - { + ) if self.infcx.can_sub(self.param_env, checked, &expected).is_ok() => { // We have `&T`, check if what was expected was `T`. If so, // we may want to suggest removing a `&`. if sm.is_imported(expr.span) { @@ -589,13 +585,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } return None; } - if let Ok(code) = sm.span_to_snippet(expr.span) { - return Some(( - sp, - "consider removing the borrow", - code, - Applicability::MachineApplicable, - )); + if sp.contains(expr.span) { + if let Ok(code) = sm.span_to_snippet(expr.span) { + return Some(( + sp, + "consider removing the borrow", + code, + Applicability::MachineApplicable, + )); + } } } ( @@ -643,7 +641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } } - _ if sp == expr.span && !is_macro => { + _ if sp == expr.span => { if let Some(steps) = self.deref_steps(checked_ty, expected) { let expr = expr.peel_blocks(); diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index 4de8216884a..96569ae0e77 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -1522,7 +1522,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = tcx.type_of(impl_def_id); let impl_ty = self.instantiate_type_scheme(span, &substs, ty); - match self.at(&self.misc(span), self.param_env).sup(impl_ty, self_ty) { + match self.at(&self.misc(span), self.param_env).eq(impl_ty, self_ty) { Ok(ok) => self.register_infer_ok_obligations(ok), Err(_) => { self.tcx.sess.delay_span_bug( diff --git a/compiler/rustc_typeck/src/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs index e40aa914858..5f26e701c0a 100644 --- a/compiler/rustc_typeck/src/check/generator_interior.rs +++ b/compiler/rustc_typeck/src/check/generator_interior.rs @@ -89,19 +89,31 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> { if let Some((unresolved_type, unresolved_type_span)) = self.fcx.unresolved_type_vars(&ty) { - let note = format!( - "the type is part of the {} because of this {}", - self.kind, yield_data.source - ); - // If unresolved type isn't a ty_var then unresolved_type_span is None let span = self .prev_unresolved_span .unwrap_or_else(|| unresolved_type_span.unwrap_or(source_span)); - self.fcx - .need_type_info_err_in_generator(self.kind, span, unresolved_type) - .span_note(yield_data.span, &*note) - .emit(); + + // If we encounter an int/float variable, then inference fallback didn't + // finish due to some other error. Don't emit spurious additional errors. + if let ty::Infer(ty::InferTy::IntVar(_) | ty::InferTy::FloatVar(_)) = + unresolved_type.kind() + { + self.fcx + .tcx + .sess + .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_type)); + } else { + let note = format!( + "the type is part of the {} because of this {}", + self.kind, yield_data.source + ); + + self.fcx + .need_type_info_err_in_generator(self.kind, span, unresolved_type) + .span_note(yield_data.span, &*note) + .emit(); + } } else { // Insert the type into the ordered set. let scope_span = scope.map(|s| s.span(self.fcx.tcx, self.region_scope_tree)); diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 0b1129a6312..427102afee1 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -303,8 +303,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { opt_input_types: Option<&[Ty<'tcx>]>, ) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> { debug!( - "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?})", - self_ty, m_name, trait_def_id + "lookup_in_trait_adjusted(self_ty={:?}, m_name={}, trait_def_id={:?}, opt_input_types={:?})", + self_ty, m_name, trait_def_id, opt_input_types ); // Construct a trait-reference `self_ty : Trait<input_tys>` diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 2320a29e6d8..16382c7e7a4 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -383,6 +383,42 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } else { span = item_name.span; + + // Don't show generic arguments when the method can't be found in any implementation (#81576). + let mut ty_str_reported = ty_str.clone(); + if let ty::Adt(_, ref generics) = actual.kind() { + if generics.len() > 0 { + let mut autoderef = self.autoderef(span, actual); + let candidate_found = autoderef.any(|(ty, _)| { + if let ty::Adt(ref adt_deref, _) = ty.kind() { + self.tcx + .inherent_impls(adt_deref.did) + .iter() + .filter_map(|def_id| { + self.associated_item( + *def_id, + item_name, + Namespace::ValueNS, + ) + }) + .count() + >= 1 + } else { + false + } + }); + let has_deref = autoderef.step_count() > 0; + if !candidate_found + && !has_deref + && unsatisfied_predicates.is_empty() + { + if let Some((path_string, _)) = ty_str.split_once('<') { + ty_str_reported = path_string.to_string(); + } + } + } + } + let mut err = struct_span_err!( tcx.sess, span, @@ -391,7 +427,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { item_kind, item_name, actual.prefix_string(self.tcx), - ty_str, + ty_str_reported, ); if let Mode::MethodCall = mode { if let SelfSource::MethodCall(call) = source { @@ -449,6 +485,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut label_span_not_found = || { if unsatisfied_predicates.is_empty() { err.span_label(span, format!("{item_kind} not found in `{ty_str}`")); + if let ty::Adt(ref adt, _) = rcvr_ty.kind() { + let mut inherent_impls_candidate = self + .tcx + .inherent_impls(adt.did) + .iter() + .copied() + .filter(|def_id| { + if let Some(assoc) = + self.associated_item(*def_id, item_name, Namespace::ValueNS) + { + // Check for both mode is the same so we avoid suggesting + // incorrect associated item. + match (mode, assoc.fn_has_self_parameter, source) { + (Mode::MethodCall, true, SelfSource::MethodCall(_)) => { + // We check that the suggest type is actually + // different from the received one + // So we avoid suggestion method with Box<Self> + // for instance + self.tcx.at(span).type_of(*def_id) != actual + && self.tcx.at(span).type_of(*def_id) != rcvr_ty + } + (Mode::Path, false, _) => true, + _ => false, + } + } else { + false + } + }) + .collect::<Vec<_>>(); + if inherent_impls_candidate.len() > 0 { + inherent_impls_candidate.sort(); + inherent_impls_candidate.dedup(); + + // number of type to shows at most. + let limit = if inherent_impls_candidate.len() == 5 { 5 } else { 4 }; + let type_candidates = inherent_impls_candidate + .iter() + .take(limit) + .map(|impl_item| { + format!("- `{}`", self.tcx.at(span).type_of(*impl_item)) + }) + .collect::<Vec<_>>() + .join("\n"); + let additional_types = if inherent_impls_candidate.len() > limit { + format!( + "\nand {} more types", + inherent_impls_candidate.len() - limit + ) + } else { + "".to_string() + }; + err.note(&format!( + "the {item_kind} was found for\n{}{}", + type_candidates, additional_types + )); + } + } } else { err.span_label(span, format!("{item_kind} cannot be called on `{ty_str}` due to unsatisfied trait bounds")); } diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs index d6db2e1d76f..ad7853b7cd0 100644 --- a/compiler/rustc_typeck/src/check/mod.rs +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -1187,3 +1187,14 @@ fn fatally_break_rust(sess: &Session) { fn potentially_plural_count(count: usize, word: &str) -> String { format!("{} {}{}", count, word, pluralize!(count)) } + +fn has_expected_num_generic_args<'tcx>( + tcx: TyCtxt<'tcx>, + trait_did: Option<DefId>, + expected: usize, +) -> bool { + trait_did.map_or(true, |trait_did| { + let generics = tcx.generics_of(trait_did); + generics.count() == expected + if generics.has_self { 1 } else { 0 } + }) +} diff --git a/compiler/rustc_typeck/src/check/op.rs b/compiler/rustc_typeck/src/check/op.rs index 567cb1a90d0..963436d05d8 100644 --- a/compiler/rustc_typeck/src/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -1,7 +1,7 @@ //! Code related to processing overloaded binary and unary operators. use super::method::MethodCallee; -use super::FnCtxt; +use super::{has_expected_num_generic_args, FnCtxt}; use rustc_ast as ast; use rustc_errors::{self, struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; @@ -795,6 +795,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lhs_ty, op, opname, trait_did ); + // Catches cases like #83893, where a lang item is declared with the + // wrong number of generic arguments. Should have yielded an error + // elsewhere by now, but we have to catch it here so that we do not + // index `other_tys` out of bounds (if the lang item has too many + // generic arguments, `other_tys` is too short). + if !has_expected_num_generic_args( + self.tcx, + trait_did, + match op { + // Binary ops have a generic right-hand side, unary ops don't + Op::Binary(..) => 1, + Op::Unary(..) => 0, + }, + ) { + return Err(()); + } + let method = trait_did.and_then(|trait_did| { let opname = Ident::with_dummy_span(opname); self.lookup_method_in_trait(span, opname, trait_did, lhs_ty, Some(other_tys)) diff --git a/compiler/rustc_typeck/src/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs index 5bd385107ca..652b82f1063 100644 --- a/compiler/rustc_typeck/src/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -1,5 +1,5 @@ use crate::check::method::MethodCallee; -use crate::check::{FnCtxt, PlaceOp}; +use crate::check::{has_expected_num_generic_args, FnCtxt, PlaceOp}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::InferOk; @@ -153,6 +153,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref), PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index), }; + + // If the lang item was declared incorrectly, stop here so that we don't + // run into an ICE (#83893). The error is reported where the lang item is + // declared. + if !has_expected_num_generic_args( + self.tcx, + imm_tr, + match op { + PlaceOp::Deref => 0, + PlaceOp::Index => 1, + }, + ) { + return None; + } + imm_tr.and_then(|trait_did| { self.lookup_method_in_trait( span, @@ -177,6 +192,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PlaceOp::Deref => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut), PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut), }; + + // If the lang item was declared incorrectly, stop here so that we don't + // run into an ICE (#83893). The error is reported where the lang item is + // declared. + if !has_expected_num_generic_args( + self.tcx, + mut_tr, + match op { + PlaceOp::Deref => 0, + PlaceOp::Index => 1, + }, + ) { + return None; + } + mut_tr.and_then(|trait_did| { self.lookup_method_in_trait( span, @@ -218,7 +248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Clear previous flag; after a pointer indirection it does not apply any more. inside_union = false; } - if source.ty_adt_def().map_or(false, |adt| adt.is_union()) { + if source.is_union() { inside_union = true; } // Fix up the autoderefs. Autorefs can only occur immediately preceding diff --git a/compiler/rustc_typeck/src/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs index ff506ef8727..6baa185406e 100644 --- a/compiler/rustc_typeck/src/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -323,7 +323,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// /// InferBorrowKind results in a structure like this: /// - /// ``` + /// ```text /// { /// Place(base: hir_id_s, projections: [], ....) -> { /// capture_kind_expr: hir_id_L5, @@ -348,7 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// ``` /// /// After the min capture analysis, we get: - /// ``` + /// ```text /// { /// hir_id_s -> [ /// Place(base: hir_id_s, projections: [], ....) -> { @@ -1588,6 +1588,11 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) { if let PlaceBase::Upvar(_) = place.base { + // We need to restrict Fake Read precision to avoid fake reading unsafe code, + // such as deref of a raw pointer. + let place = restrict_capture_precision(place); + let place = + restrict_repr_packed_field_ref_capture(self.fcx.tcx, self.fcx.param_env, &place); self.fake_reads.push((place, cause, diag_expr_id)); } } diff --git a/compiler/rustc_typeck/src/collect.rs b/compiler/rustc_typeck/src/collect.rs index 0528f8812f9..5d83375e5a1 100644 --- a/compiler/rustc_typeck/src/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -2770,7 +2770,21 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { } } else if tcx.sess.check_name(attr, sym::target_feature) { if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { - if !tcx.features().target_feature_11 { + if tcx.sess.target.is_like_wasm { + // The `#[target_feature]` attribute is allowed on + // WebAssembly targets on all functions, including safe + // ones. Other targets require that `#[target_feature]` is + // only applied to unsafe funtions (pending the + // `target_feature_11` feature) because on most targets + // execution of instructions that are not supported is + // considered undefined behavior. For WebAssembly which is a + // 100% safe target at execution time it's not possible to + // execute undefined instructions, and even if a future + // feature was added in some form for this it would be a + // deterministic trap. There is no undefined behavior when + // executing WebAssembly so `#[target_feature]` is allowed + // on safe functions (but again, only for WebAssembly) + } else if !tcx.features().target_feature_11 { let mut err = feature_err( &tcx.sess.parse_sess, sym::target_feature_11, diff --git a/compiler/rustc_typeck/src/lib.rs b/compiler/rustc_typeck/src/lib.rs index 47299722325..92ef8297472 100644 --- a/compiler/rustc_typeck/src/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -65,7 +65,6 @@ This API is completely unstable and subject to change. #![feature(is_sorted)] #![feature(iter_zip)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(try_blocks)] #![feature(never_type)] #![feature(slice_partition_dedup)] diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index 56f288ff051..bccc19774e0 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -509,44 +509,23 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { } AngleBrackets::Available => { - // angle brackets exist, so we insert missing arguments after the existing args - - assert!(!self.gen_args.args.is_empty()); - - if self.num_provided_lifetime_args() > 0 { - let last_lt_arg_span = self.gen_args.args - [self.num_provided_lifetime_args() - 1] - .span() - .shrink_to_hi(); - let source_map = self.tcx.sess.source_map(); - - if let Ok(last_gen_arg) = source_map.span_to_snippet(last_lt_arg_span) { - let sugg = format!("{}, {}", last_gen_arg, suggested_args); - - err.span_suggestion_verbose( - last_lt_arg_span, - &msg, - sugg, - Applicability::HasPlaceholders, - ); - } + let (sugg_span, is_first) = if self.num_provided_lifetime_args() == 0 { + (self.gen_args.span().unwrap().shrink_to_lo(), true) } else { - // Non-lifetime arguments included in `gen_args` -> insert missing lifetimes before - // existing arguments - let first_arg_span = self.gen_args.args[0].span().shrink_to_lo(); - let source_map = self.tcx.sess.source_map(); - - if let Ok(first_gen_arg) = source_map.span_to_snippet(first_arg_span) { - let sugg = format!("{}, {}", suggested_args, first_gen_arg); - - err.span_suggestion_verbose( - first_arg_span, - &msg, - sugg, - Applicability::HasPlaceholders, - ); - } - } + let last_lt = &self.gen_args.args[self.num_provided_lifetime_args() - 1]; + (last_lt.span().shrink_to_hi(), false) + }; + let has_non_lt_args = self.num_provided_type_or_const_args() != 0; + let has_bindings = !self.gen_args.bindings.is_empty(); + + let sugg_prefix = if is_first { "" } else { ", " }; + let sugg_suffix = + if is_first && (has_non_lt_args || has_bindings) { ", " } else { "" }; + + let sugg = format!("{}{}{}", sugg_prefix, suggested_args, sugg_suffix); + debug!("sugg: {:?}", sugg); + + err.span_suggestion_verbose(sugg_span, &msg, sugg, Applicability::HasPlaceholders); } AngleBrackets::Implied => { // We never encounter missing lifetimes in situations in which lifetimes are elided @@ -626,30 +605,35 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { let remove_entire_generics = num_redundant_args >= self.gen_args.args.len(); let remove_lifetime_args = |err: &mut DiagnosticBuilder<'_>| { - let idx_first_redundant_lt_args = self.num_expected_lifetime_args(); - let span_lo_redundant_lt_args = - self.gen_args.args[idx_first_redundant_lt_args].span().shrink_to_lo(); - let span_hi_redundant_lt_args = self.gen_args.args - [idx_first_redundant_lt_args + num_redundant_lt_args - 1] - .span() - .shrink_to_hi(); - let eat_comma = - idx_first_redundant_lt_args + num_redundant_lt_args - 1 != self.gen_args.args.len(); - - let span_redundant_lt_args = if eat_comma { - let span_hi = self.gen_args.args - [idx_first_redundant_lt_args + num_redundant_lt_args - 1] - .span() - .shrink_to_hi(); - span_lo_redundant_lt_args.to(span_hi) - } else { - span_lo_redundant_lt_args.to(span_hi_redundant_lt_args) - }; + let mut lt_arg_spans = Vec::new(); + let mut found_redundant = false; + for arg in self.gen_args.args { + if let hir::GenericArg::Lifetime(_) = arg { + lt_arg_spans.push(arg.span()); + if lt_arg_spans.len() > self.num_expected_lifetime_args() { + found_redundant = true; + } + } else if found_redundant { + // Argument which is redundant and separated like this `'c` + // is not included to avoid including `Bar` in span. + // ``` + // type Foo<'a, T> = &'a T; + // let _: Foo<'a, 'b, Bar, 'c>; + // ``` + break; + } + } + + let span_lo_redundant_lt_args = lt_arg_spans[self.num_expected_lifetime_args()]; + let span_hi_redundant_lt_args = lt_arg_spans[lt_arg_spans.len() - 1]; + + let span_redundant_lt_args = span_lo_redundant_lt_args.to(span_hi_redundant_lt_args); debug!("span_redundant_lt_args: {:?}", span_redundant_lt_args); + let num_redundant_lt_args = lt_arg_spans.len() - self.num_expected_lifetime_args(); let msg_lifetimes = format!( "remove {} {} argument{}", - if num_redundant_args == 1 { "this" } else { "these" }, + if num_redundant_lt_args == 1 { "this" } else { "these" }, "lifetime", pluralize!(num_redundant_lt_args), ); @@ -663,26 +647,34 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> { }; let remove_type_or_const_args = |err: &mut DiagnosticBuilder<'_>| { - let idx_first_redundant_type_or_const_args = self.get_lifetime_args_offset() - + num_redundant_lt_args - + self.num_expected_type_or_const_args(); + let mut gen_arg_spans = Vec::new(); + let mut found_redundant = false; + for arg in self.gen_args.args { + match arg { + hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => { + gen_arg_spans.push(arg.span()); + if gen_arg_spans.len() > self.num_expected_type_or_const_args() { + found_redundant = true; + } + } + _ if found_redundant => break, + _ => {} + } + } let span_lo_redundant_type_or_const_args = - self.gen_args.args[idx_first_redundant_type_or_const_args].span().shrink_to_lo(); - - let span_hi_redundant_type_or_const_args = self.gen_args.args - [idx_first_redundant_type_or_const_args + num_redundant_type_or_const_args - 1] - .span() - .shrink_to_hi(); + gen_arg_spans[self.num_expected_type_or_const_args()]; + let span_hi_redundant_type_or_const_args = gen_arg_spans[gen_arg_spans.len() - 1]; let span_redundant_type_or_const_args = span_lo_redundant_type_or_const_args.to(span_hi_redundant_type_or_const_args); - debug!("span_redundant_type_or_const_args: {:?}", span_redundant_type_or_const_args); + let num_redundant_gen_args = + gen_arg_spans.len() - self.num_expected_type_or_const_args(); let msg_types_or_consts = format!( "remove {} {} argument{}", - if num_redundant_args == 1 { "this" } else { "these" }, + if num_redundant_gen_args == 1 { "this" } else { "these" }, "generic", pluralize!(num_redundant_type_or_const_args), ); diff --git a/config.toml.example b/config.toml.example index 16952a5ced8..df2fb448b7d 100644 --- a/config.toml.example +++ b/config.toml.example @@ -563,6 +563,14 @@ changelog-seen = 2 # Use LLVM libunwind as the implementation for Rust's unwinder. # Accepted values are 'in-tree' (formerly true), 'system' or 'no' (formerly false). +# This option only applies for Linux and Fuchsia targets. +# On Linux target, if crt-static is not enabled, 'no' means dynamic link to +# `libgcc_s.so`, 'in-tree' means static link to the in-tree build of llvm libunwind +# and 'system' means dynamic link to `libunwind.so`. If crt-static is enabled, +# the behavior is depend on the libc. On musl target, 'no' and 'in-tree' both +# means static link to the in-tree build of llvm libunwind, and 'system' means +# static link to `libunwind.a` provided by system. Due to the limitation of glibc, +# it must link to `libgcc_eh.a` to get a working output, and this option have no effect. #llvm-libunwind = 'no' # Enable Windows Control Flow Guard checks in the standard library. diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index 48709e89823..c9bdcaa78f3 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -468,7 +468,6 @@ fn bench_in_place_recycle(b: &mut Bencher) { .enumerate() .map(|(idx, e)| idx.wrapping_add(e)) .fuse() - .peekable() .collect::<Vec<usize>>(), ); }); diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index a5481fd175e..1a58ad51f78 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -64,7 +64,15 @@ pub struct Iter<'a, T: 'a> { #[stable(feature = "collection_debug", since = "1.17.0")] impl<T: fmt::Debug> fmt::Debug for Iter<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Iter").field(&self.len).finish() + f.debug_tuple("Iter") + .field(&*mem::ManuallyDrop::new(LinkedList { + head: self.head, + tail: self.tail, + len: self.len, + marker: PhantomData, + })) + .field(&self.len) + .finish() } } @@ -82,19 +90,24 @@ impl<T> Clone for Iter<'_, T> { /// documentation for more. #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { - // We do *not* exclusively own the entire list here, references to node's `element` - // have been handed out by the iterator! So be careful when using this; the methods - // called must be aware that there can be aliasing pointers to `element`. - list: &'a mut LinkedList<T>, head: Option<NonNull<Node<T>>>, tail: Option<NonNull<Node<T>>>, len: usize, + marker: PhantomData<&'a mut Node<T>>, } #[stable(feature = "collection_debug", since = "1.17.0")] impl<T: fmt::Debug> fmt::Debug for IterMut<'_, T> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("IterMut").field(&self.list).field(&self.len).finish() + f.debug_tuple("IterMut") + .field(&*mem::ManuallyDrop::new(LinkedList { + head: self.head, + tail: self.tail, + len: self.len, + marker: PhantomData, + })) + .field(&self.len) + .finish() } } @@ -442,27 +455,6 @@ impl<T> LinkedList<T> { } } - /// Moves all elements from `other` to the begin of the list. - #[unstable(feature = "linked_list_prepend", issue = "none")] - pub fn prepend(&mut self, other: &mut Self) { - match self.head { - None => mem::swap(self, other), - Some(mut head) => { - // `as_mut` is okay here because we have exclusive access to the entirety - // of both lists. - if let Some(mut other_tail) = other.tail.take() { - unsafe { - head.as_mut().prev = Some(other_tail); - other_tail.as_mut().next = Some(head); - } - - self.head = other.head.take(); - self.len += mem::replace(&mut other.len, 0); - } - } - } - } - /// Provides a forward iterator. /// /// # Examples @@ -514,7 +506,7 @@ impl<T> LinkedList<T> { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter_mut(&mut self) -> IterMut<'_, T> { - IterMut { head: self.head, tail: self.tail, len: self.len, list: self } + IterMut { head: self.head, tail: self.tail, len: self.len, marker: PhantomData } } /// Provides a cursor at the front element. diff --git a/library/alloc/src/collections/vec_deque/iter.rs b/library/alloc/src/collections/vec_deque/iter.rs index e4cfb3acdfd..f3eb228c9e3 100644 --- a/library/alloc/src/collections/vec_deque/iter.rs +++ b/library/alloc/src/collections/vec_deque/iter.rs @@ -66,7 +66,7 @@ impl<'a, T> Iterator for Iter<'a, T> { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { let (mut iter, final_res); if self.tail <= self.head { @@ -140,7 +140,7 @@ impl<'a, T> DoubleEndedIterator for Iter<'a, T> { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { let (mut iter, final_res); if self.tail <= self.head { diff --git a/library/alloc/src/collections/vec_deque/mod.rs b/library/alloc/src/collections/vec_deque/mod.rs index 7d6fbf1c438..5d03be35e46 100644 --- a/library/alloc/src/collections/vec_deque/mod.rs +++ b/library/alloc/src/collections/vec_deque/mod.rs @@ -2416,7 +2416,6 @@ impl<T> VecDeque<T> { /// found; the fourth could match any position in `[1, 4]`. /// /// ``` - /// #![feature(vecdeque_binary_search)] /// use std::collections::VecDeque; /// /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); @@ -2432,7 +2431,6 @@ impl<T> VecDeque<T> { /// sort order: /// /// ``` - /// #![feature(vecdeque_binary_search)] /// use std::collections::VecDeque; /// /// let mut deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); @@ -2441,7 +2439,7 @@ impl<T> VecDeque<T> { /// deque.insert(idx, num); /// assert_eq!(deque, &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 42, 55]); /// ``` - #[unstable(feature = "vecdeque_binary_search", issue = "78021")] + #[stable(feature = "vecdeque_binary_search", since = "1.54.0")] #[inline] pub fn binary_search(&self, x: &T) -> Result<usize, usize> where @@ -2476,7 +2474,6 @@ impl<T> VecDeque<T> { /// found; the fourth could match any position in `[1, 4]`. /// /// ``` - /// #![feature(vecdeque_binary_search)] /// use std::collections::VecDeque; /// /// let deque: VecDeque<_> = vec![0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55].into(); @@ -2487,7 +2484,7 @@ impl<T> VecDeque<T> { /// let r = deque.binary_search_by(|x| x.cmp(&1)); /// assert!(matches!(r, Ok(1..=4))); /// ``` - #[unstable(feature = "vecdeque_binary_search", issue = "78021")] + #[stable(feature = "vecdeque_binary_search", since = "1.54.0")] pub fn binary_search_by<'a, F>(&'a self, mut f: F) -> Result<usize, usize> where F: FnMut(&'a T) -> Ordering, @@ -2530,7 +2527,6 @@ impl<T> VecDeque<T> { /// fourth could match any position in `[1, 4]`. /// /// ``` - /// #![feature(vecdeque_binary_search)] /// use std::collections::VecDeque; /// /// let deque: VecDeque<_> = vec![(0, 0), (2, 1), (4, 1), (5, 1), @@ -2543,7 +2539,7 @@ impl<T> VecDeque<T> { /// let r = deque.binary_search_by_key(&1, |&(a, b)| b); /// assert!(matches!(r, Ok(1..=4))); /// ``` - #[unstable(feature = "vecdeque_binary_search", issue = "78021")] + #[stable(feature = "vecdeque_binary_search", since = "1.54.0")] #[inline] pub fn binary_search_by_key<'a, B, F>(&'a self, b: &B, mut f: F) -> Result<usize, usize> where @@ -2574,7 +2570,6 @@ impl<T> VecDeque<T> { /// # Examples /// /// ``` - /// #![feature(vecdeque_binary_search)] /// use std::collections::VecDeque; /// /// let deque: VecDeque<_> = vec![1, 2, 3, 3, 5, 6, 7].into(); @@ -2584,7 +2579,7 @@ impl<T> VecDeque<T> { /// assert!(deque.iter().take(i).all(|&x| x < 5)); /// assert!(deque.iter().skip(i).all(|&x| !(x < 5))); /// ``` - #[unstable(feature = "vecdeque_binary_search", issue = "78021")] + #[stable(feature = "vecdeque_binary_search", since = "1.54.0")] pub fn partition_point<P>(&self, mut pred: P) -> usize where P: FnMut(&T) -> bool, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 66b1036f2ab..7bc9aa69be9 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -88,8 +88,7 @@ #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] #![cfg_attr(not(no_global_oom_handling), feature(const_btree_new))] -#![cfg_attr(bootstrap, feature(const_fn))] -#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))] +#![feature(const_fn_trait_bound)] #![feature(cow_is_borrowed)] #![feature(const_cow_is_borrowed)] #![feature(destructuring_assignment)] @@ -118,7 +117,6 @@ #![feature(nonnull_slice_from_raw_parts)] #![feature(auto_traits)] #![feature(option_result_unwrap_unchecked)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(pattern)] #![feature(ptr_internals)] #![feature(rustc_attrs)] @@ -140,11 +138,13 @@ #![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)] #![feature(alloc_layout_extra)] #![feature(trusted_random_access)] -#![feature(try_trait)] +#![cfg_attr(bootstrap, feature(try_trait))] +#![cfg_attr(not(bootstrap), feature(try_trait_v2))] #![feature(min_type_alias_impl_trait)] #![feature(associated_type_bounds)] #![feature(slice_group_by)] #![feature(decl_macro)] +#![feature(bindings_after_at)] // Allow testing this library #[cfg(test)] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 800952f7a5e..f131182a896 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1859,6 +1859,18 @@ where B: ToOwned + ?Sized, Rc<B>: From<&'a B> + From<B::Owned>, { + /// Create a reference-counted pointer from + /// a clone-on-write pointer by copying its content. + /// + /// # Example + /// + /// ```rust + /// # use std::rc::Rc; + /// # use std::borrow::Cow; + /// let cow: Cow<str> = Cow::Borrowed("eggplant"); + /// let shared: Rc<str> = Rc::from(cow); + /// assert_eq!("eggplant", &shared[..]); + /// ``` #[inline] fn from(cow: Cow<'a, B>) -> Rc<B> { match cow { @@ -2303,7 +2315,7 @@ impl<T: ?Sized> Weak<T> { } #[stable(feature = "rc_weak", since = "1.4.0")] -impl<T: ?Sized> Drop for Weak<T> { +unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> { /// Drops the `Weak` pointer. /// /// # Examples diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index e6252452470..dbe5bc1da46 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -843,6 +843,42 @@ impl String { self.vec.extend_from_slice(string.as_bytes()) } + /// Copies elements from `src` range to the end of the string. + /// + /// ## Panics + /// + /// Panics if the starting point or end point do not lie on a [`char`] + /// boundary, or if they're out of bounds. + /// + /// ## Examples + /// + /// ``` + /// #![feature(string_extend_from_within)] + /// let mut string = String::from("abcde"); + /// + /// string.extend_from_within(2..); + /// assert_eq!(string, "abcdecde"); + /// + /// string.extend_from_within(..2); + /// assert_eq!(string, "abcdecdeab"); + /// + /// string.extend_from_within(4..8); + /// assert_eq!(string, "abcdecdeabecde"); + /// ``` + #[cfg(not(no_global_oom_handling))] + #[unstable(feature = "string_extend_from_within", issue = "none")] + pub fn extend_from_within<R>(&mut self, src: R) + where + R: RangeBounds<usize>, + { + let src @ Range { start, end } = slice::range(src, ..self.len()); + + assert!(self.is_char_boundary(start)); + assert!(self.is_char_boundary(end)); + + self.vec.extend_from_within(src); + } + /// Returns this `String`'s capacity, in bytes. /// /// # Examples @@ -2323,9 +2359,10 @@ impl<T: fmt::Display + ?Sized> ToString for T { // to try to remove it. #[inline] default fn to_string(&self) -> String { - use fmt::Write; let mut buf = String::new(); - buf.write_fmt(format_args!("{}", self)) + let mut formatter = core::fmt::Formatter::new(&mut buf); + // Bypass format_args!() to avoid write_str with zero-length strs + fmt::Display::fmt(self, &mut formatter) .expect("a Display implementation returned an error unexpectedly"); buf } diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 17927f5f5fd..a8fa028fc90 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2015,7 +2015,7 @@ impl<T> Default for Weak<T> { } #[stable(feature = "arc_weak", since = "1.4.0")] -impl<T: ?Sized> Drop for Weak<T> { +unsafe impl<#[may_dangle] T: ?Sized> Drop for Weak<T> { /// Drops the `Weak` pointer. /// /// # Examples @@ -2413,6 +2413,18 @@ where B: ToOwned + ?Sized, Arc<B>: From<&'a B> + From<B::Owned>, { + /// Create an atomically reference-counted pointer from + /// a clone-on-write pointer by copying its content. + /// + /// # Example + /// + /// ```rust + /// # use std::sync::Arc; + /// # use std::borrow::Cow; + /// let cow: Cow<str> = Cow::Borrowed("eggplant"); + /// let shared: Arc<str> = Arc::from(cow); + /// assert_eq!("eggplant", &shared[..]); + /// ``` #[inline] fn from(cow: Cow<'a, B>) -> Arc<B> { match cow { diff --git a/library/alloc/src/vec/cow.rs b/library/alloc/src/vec/cow.rs index 73d15d30647..64943a273c9 100644 --- a/library/alloc/src/vec/cow.rs +++ b/library/alloc/src/vec/cow.rs @@ -5,6 +5,12 @@ use super::Vec; #[stable(feature = "cow_from_vec", since = "1.8.0")] impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> { + /// Creates a [`Borrowed`] variant of [`Cow`] + /// from a slice. + /// + /// This conversion does not allocate or clone the data. + /// + /// [`Borrowed`]: crate::borrow::Cow::Borrowed fn from(s: &'a [T]) -> Cow<'a, [T]> { Cow::Borrowed(s) } @@ -12,6 +18,12 @@ impl<'a, T: Clone> From<&'a [T]> for Cow<'a, [T]> { #[stable(feature = "cow_from_vec", since = "1.8.0")] impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> { + /// Creates an [`Owned`] variant of [`Cow`] + /// from an owned instance of [`Vec`]. + /// + /// This conversion does not allocate or clone the data. + /// + /// [`Owned`]: crate::borrow::Cow::Owned fn from(v: Vec<T>) -> Cow<'a, [T]> { Cow::Owned(v) } @@ -19,6 +31,12 @@ impl<'a, T: Clone> From<Vec<T>> for Cow<'a, [T]> { #[stable(feature = "cow_from_vec_ref", since = "1.28.0")] impl<'a, T: Clone> From<&'a Vec<T>> for Cow<'a, [T]> { + /// Creates a [`Borrowed`] variant of [`Cow`] + /// from a reference to [`Vec`]. + /// + /// This conversion does not allocate or clone the data. + /// + /// [`Borrowed`]: crate::borrow::Cow::Borrowed fn from(v: &'a Vec<T>) -> Cow<'a, [T]> { Cow::Borrowed(v.as_slice()) } diff --git a/library/alloc/src/vec/is_zero.rs b/library/alloc/src/vec/is_zero.rs index b5739970b6e..0efc4893c3c 100644 --- a/library/alloc/src/vec/is_zero.rs +++ b/library/alloc/src/vec/is_zero.rs @@ -69,3 +69,36 @@ unsafe impl<T: ?Sized> IsZero for Option<Box<T>> { self.is_none() } } + +// `Option<num::NonZeroU32>` and similar have a representation guarantee that +// they're the same size as the corresponding `u32` type, as well as a guarantee +// that transmuting between `NonZeroU32` and `Option<num::NonZeroU32>` works. +// While the documentation officially makes it UB to transmute from `None`, +// we're the standard library so we can make extra inferences, and we know that +// the only niche available to represent `None` is the one that's all zeros. + +macro_rules! impl_is_zero_option_of_nonzero { + ($($t:ident,)+) => {$( + unsafe impl IsZero for Option<core::num::$t> { + #[inline] + fn is_zero(&self) -> bool { + self.is_none() + } + } + )+}; +} + +impl_is_zero_option_of_nonzero!( + NonZeroU8, + NonZeroU16, + NonZeroU32, + NonZeroU64, + NonZeroU128, + NonZeroI8, + NonZeroI16, + NonZeroI32, + NonZeroI64, + NonZeroI128, + NonZeroUsize, + NonZeroIsize, +); diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 1c33ff555d6..105c60e7bf0 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -1619,6 +1619,8 @@ impl<T, A: Allocator> Vec<T, A> { let prev_ptr = ptr.add(gap.write.wrapping_sub(1)); if same_bucket(&mut *read_ptr, &mut *prev_ptr) { + // Increase `gap.read` now since the drop may panic. + gap.read += 1; /* We have found duplicate, drop it in-place */ ptr::drop_in_place(read_ptr); } else { @@ -1631,9 +1633,8 @@ impl<T, A: Allocator> Vec<T, A> { /* We have filled that place, so go further */ gap.write += 1; + gap.read += 1; } - - gap.read += 1; } /* Technically we could let `gap` clean up with its Drop, but diff --git a/library/alloc/src/vec/spec_from_iter.rs b/library/alloc/src/vec/spec_from_iter.rs index bbfcc68daef..efa6868473e 100644 --- a/library/alloc/src/vec/spec_from_iter.rs +++ b/library/alloc/src/vec/spec_from_iter.rs @@ -1,6 +1,5 @@ use core::mem::ManuallyDrop; use core::ptr::{self}; -use core::slice::{self}; use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec}; @@ -19,9 +18,7 @@ use super::{IntoIter, SpecExtend, SpecFromIterNested, Vec}; /// |where I: | | |where I: | /// | Iterator (default)----------+ | | Iterator (default) | /// | vec::IntoIter | | | TrustedLen | -/// | SourceIterMarker---fallback-+ | | | -/// | slice::Iter | | | -/// | Iterator<Item = &Clone> | +---------------------+ +/// | SourceIterMarker---fallback-+ | +---------------------+ /// +---------------------------------+ /// ``` pub(super) trait SpecFromIter<T, I> { @@ -65,33 +62,3 @@ impl<T> SpecFromIter<T, IntoIter<T>> for Vec<T> { vec } } - -impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec<T> -where - I: Iterator<Item = &'a T>, - T: Clone, -{ - default fn from_iter(iterator: I) -> Self { - SpecFromIter::from_iter(iterator.cloned()) - } -} - -// This utilizes `iterator.as_slice().to_vec()` since spec_extend -// must take more steps to reason about the final capacity + length -// and thus do more work. `to_vec()` directly allocates the correct amount -// and fills it exactly. -impl<'a, T: 'a + Clone> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec<T> { - #[cfg(not(test))] - fn from_iter(iterator: slice::Iter<'a, T>) -> Self { - iterator.as_slice().to_vec() - } - - // HACK(japaric): with cfg(test) the inherent `[T]::to_vec` method, which is - // required for this method definition, is not available. Instead use the - // `slice::to_vec` function which is only available with cfg(test) - // NB see the slice::hack module in slice.rs for more information - #[cfg(test)] - fn from_iter(iterator: slice::Iter<'a, T>) -> Self { - crate::slice::to_vec(iterator.as_slice(), crate::alloc::Global) - } -} diff --git a/library/alloc/tests/arc.rs b/library/alloc/tests/arc.rs index c02ba267056..ce40b5c9b0a 100644 --- a/library/alloc/tests/arc.rs +++ b/library/alloc/tests/arc.rs @@ -195,3 +195,18 @@ fn shared_from_iter_trustedlen_no_fuse() { assert_trusted_len(&iter); assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>()); } + +#[test] +fn weak_may_dangle() { + fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> { + val.clone() + } + + // Without #[may_dangle] we get: + let mut val = Weak::new(); + hmm(&mut val); + // ~~~~~~~~ borrowed value does not live long enough + // + // `val` dropped here while still borrowed + // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::sync::Weak` +} diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index 25a83a0b014..3143afa269d 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -17,7 +17,6 @@ #![feature(binary_heap_as_slice)] #![feature(inplace_iteration)] #![feature(iter_map_while)] -#![feature(vecdeque_binary_search)] #![feature(slice_group_by)] #![feature(slice_partition_dedup)] #![feature(vec_spare_capacity)] diff --git a/library/alloc/tests/rc.rs b/library/alloc/tests/rc.rs index 501b4f0f816..efb39a60966 100644 --- a/library/alloc/tests/rc.rs +++ b/library/alloc/tests/rc.rs @@ -191,3 +191,18 @@ fn shared_from_iter_trustedlen_no_fuse() { assert_trusted_len(&iter); assert_eq!(&[Box::new(42), Box::new(24)], &*iter.collect::<Rc<[_]>>()); } + +#[test] +fn weak_may_dangle() { + fn hmm<'a>(val: &'a mut Weak<&'a str>) -> Weak<&'a str> { + val.clone() + } + + // Without #[may_dangle] we get: + let mut val = Weak::new(); + hmm(&mut val); + // ~~~~~~~~ borrowed value does not live long enough + // + // `val` dropped here while still borrowed + // borrow might be used here, when `val` is dropped and runs the `Drop` code for type `std::rc::Weak` +} diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index 4dcc5d30deb..36c81b49709 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1002,7 +1002,6 @@ fn test_from_iter_specialization_with_iterator_adapters() { .zip(std::iter::repeat(1usize)) .map(|(a, b)| a + b) .map_while(Option::Some) - .peekable() .skip(1) .map(|e| if e != usize::MAX { Ok(std::num::NonZeroUsize::new(e)) } else { Err(()) }); assert_in_place_trait(&iter); @@ -1095,6 +1094,18 @@ fn test_from_iter_specialization_panic_during_drop_leaks() { } } +// regression test for issue #85322. Peekable previously implemented InPlaceIterable, +// but due to an interaction with IntoIter's current Clone implementation it failed to uphold +// the contract. +#[test] +fn test_collect_after_iterator_clone() { + let v = vec![0; 5]; + let mut i = v.into_iter().map(|i| i + 1).peekable(); + i.peek(); + let v = i.clone().collect::<Vec<_>>(); + assert_eq!(v, [1, 1, 1, 1, 1]); + assert!(v.len() <= v.capacity()); +} #[test] fn test_cow_from() { let borrowed: &[_] = &["borrowed", "(slice)"]; @@ -2223,48 +2234,50 @@ fn test_vec_dedup() { #[test] fn test_vec_dedup_panicking() { #[derive(Debug)] - struct Panic { - drop_counter: &'static AtomicU32, + struct Panic<'a> { + drop_counter: &'a Cell<u32>, value: bool, index: usize, } - impl PartialEq for Panic { + impl<'a> PartialEq for Panic<'a> { fn eq(&self, other: &Self) -> bool { self.value == other.value } } - impl Drop for Panic { + impl<'a> Drop for Panic<'a> { fn drop(&mut self) { - let x = self.drop_counter.fetch_add(1, Ordering::SeqCst); - assert!(x != 4); + self.drop_counter.set(self.drop_counter.get() + 1); + if !std::thread::panicking() { + assert!(self.index != 4); + } } } - static DROP_COUNTER: AtomicU32 = AtomicU32::new(0); + let drop_counter = &Cell::new(0); let expected = [ - Panic { drop_counter: &DROP_COUNTER, value: false, index: 0 }, - Panic { drop_counter: &DROP_COUNTER, value: false, index: 5 }, - Panic { drop_counter: &DROP_COUNTER, value: true, index: 6 }, - Panic { drop_counter: &DROP_COUNTER, value: true, index: 7 }, + Panic { drop_counter, value: false, index: 0 }, + Panic { drop_counter, value: false, index: 5 }, + Panic { drop_counter, value: true, index: 6 }, + Panic { drop_counter, value: true, index: 7 }, ]; let mut vec = vec![ - Panic { drop_counter: &DROP_COUNTER, value: false, index: 0 }, + Panic { drop_counter, value: false, index: 0 }, // these elements get deduplicated - Panic { drop_counter: &DROP_COUNTER, value: false, index: 1 }, - Panic { drop_counter: &DROP_COUNTER, value: false, index: 2 }, - Panic { drop_counter: &DROP_COUNTER, value: false, index: 3 }, - Panic { drop_counter: &DROP_COUNTER, value: false, index: 4 }, - // here it panics - Panic { drop_counter: &DROP_COUNTER, value: false, index: 5 }, - Panic { drop_counter: &DROP_COUNTER, value: true, index: 6 }, - Panic { drop_counter: &DROP_COUNTER, value: true, index: 7 }, + Panic { drop_counter, value: false, index: 1 }, + Panic { drop_counter, value: false, index: 2 }, + Panic { drop_counter, value: false, index: 3 }, + Panic { drop_counter, value: false, index: 4 }, + // here it panics while dropping the item with index==4 + Panic { drop_counter, value: false, index: 5 }, + Panic { drop_counter, value: true, index: 6 }, + Panic { drop_counter, value: true, index: 7 }, ]; - let _ = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| { - vec.dedup(); - })); + let _ = catch_unwind(AssertUnwindSafe(|| vec.dedup())).unwrap_err(); + + assert_eq!(drop_counter.get(), 4); let ok = vec.iter().zip(expected.iter()).all(|(x, y)| x.index == y.index); diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index c36542f6314..aedbeab6610 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -139,7 +139,7 @@ impl<T, const N: usize> Iterator for IntoIter<T, N> { // SAFETY: Callers are only allowed to pass an index that is in bounds // Additionally Self: TrustedRandomAccess is only implemented for T: Copy which means even // multiple repeated reads of the same index would be safe and the - // values aree !Drop, thus won't suffer from double drops. + // values are !Drop, thus won't suffer from double drops. unsafe { self.data.get_unchecked(self.alive.start + idx).assume_init_read() } } } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 8b56c9560aa..e25d006d213 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -1,6 +1,4 @@ -//! Implementations of things like `Eq` for fixed-length arrays -//! up to a certain length. Eventually, we should be able to generalize -//! to all lengths. +//! Helper functions and types for fixed-length arrays. //! //! *[See also the array primitive type](array).* @@ -158,7 +156,6 @@ impl<T: fmt::Debug, const N: usize> fmt::Debug for [T; N] { // Note: the `#[rustc_skip_array_during_method_dispatch]` on `trait IntoIterator` // hides this implementation from explicit `.into_iter()` calls on editions < 2021, // so those calls will still resolve to the slice implementation, by reference. -#[cfg(not(bootstrap))] #[stable(feature = "array_into_iter_impl", since = "1.53.0")] impl<T, const N: usize> IntoIterator for [T; N] { type Item = T; diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index 4820588df25..f88a6e418c7 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -1123,6 +1123,15 @@ impl<T: Clone> Clone for RefCell<T> { fn clone(&self) -> RefCell<T> { RefCell::new(self.borrow().clone()) } + + /// # Panics + /// + /// Panics if `other` is currently mutably borrowed. + #[inline] + #[track_caller] + fn clone_from(&mut self, other: &Self) { + self.get_mut().clone_from(&other.borrow()) + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index f8b16b6f927..ecea898504d 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -274,7 +274,7 @@ pub trait Eq: PartialEq<Self> { // // This should never be implemented by hand. #[doc(hidden)] - #[cfg_attr(not(bootstrap), no_coverage)] // rust-lang/rust#84605 + #[no_coverage] // rust-lang/rust#84605 #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn assert_receiver_is_total_eq(&self) {} @@ -578,7 +578,7 @@ impl Ordering { /// v.sort_by_key(|&num| (num > 3, Reverse(num))); /// assert_eq!(v, vec![3, 2, 1, 6, 5, 4]); /// ``` -#[derive(PartialEq, Eq, Debug, Copy, Clone, Default, Hash)] +#[derive(PartialEq, Eq, Debug, Copy, Default, Hash)] #[stable(feature = "reverse_cmp_key", since = "1.19.0")] #[repr(transparent)] pub struct Reverse<T>(#[stable(feature = "reverse_cmp_key", since = "1.19.0")] pub T); @@ -616,6 +616,19 @@ impl<T: Ord> Ord for Reverse<T> { } } +#[stable(feature = "reverse_cmp_key", since = "1.19.0")] +impl<T: Clone> Clone for Reverse<T> { + #[inline] + fn clone(&self) -> Reverse<T> { + Reverse(self.0.clone()) + } + + #[inline] + fn clone_from(&mut self, other: &Self) { + self.0.clone_from(&other.0) + } +} + /// Trait for types that form a [total order](https://en.wikipedia.org/wiki/Total_order). /// /// An order is a total order if it is (for all `a`, `b` and `c`): diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 87042d95fbe..02ac4fb8006 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -221,6 +221,28 @@ pub struct Formatter<'a> { buf: &'a mut (dyn Write + 'a), } +impl<'a> Formatter<'a> { + /// Creates a new formatter with default settings. + /// + /// This can be used as a micro-optimization in cases where a full `Arguments` + /// structure (as created by `format_args!`) is not necessary; `Arguments` + /// is a little more expensive to use in simple formatting scenarios. + /// + /// Currently not intended for use outside of the standard library. + #[unstable(feature = "fmt_internals", reason = "internal to standard library", issue = "none")] + #[doc(hidden)] + pub fn new(buf: &'a mut (dyn Write + 'a)) -> Formatter<'a> { + Formatter { + flags: 0, + fill: ' ', + align: rt::v1::Alignment::Unknown, + width: None, + precision: None, + buf, + } + } +} + // NB. Argument is essentially an optimized partially applied formatting function, // equivalent to `exists T.(&T, fn(&T, &mut Formatter<'_>) -> Result`. @@ -1075,22 +1097,16 @@ pub trait UpperExp { /// [`write!`]: crate::write! #[stable(feature = "rust1", since = "1.0.0")] pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { - let mut formatter = Formatter { - flags: 0, - width: None, - precision: None, - buf: output, - align: rt::v1::Alignment::Unknown, - fill: ' ', - }; - + let mut formatter = Formatter::new(output); let mut idx = 0; match args.fmt { None => { // We can use default formatting parameters for all arguments. for (arg, piece) in iter::zip(args.args, args.pieces) { - formatter.buf.write_str(*piece)?; + if !piece.is_empty() { + formatter.buf.write_str(*piece)?; + } (arg.formatter)(arg.value, &mut formatter)?; idx += 1; } @@ -1099,7 +1115,9 @@ pub fn write(output: &mut dyn Write, args: Arguments<'_>) -> Result { // Every spec has a corresponding argument that is preceded by // a string piece. for (arg, piece) in iter::zip(fmt, args.pieces) { - formatter.buf.write_str(*piece)?; + if !piece.is_empty() { + formatter.buf.write_str(*piece)?; + } // SAFETY: arg and args.args come from the same Arguments, // which guarantees the indexes are always within bounds. unsafe { run(&mut formatter, arg, &args.args) }?; @@ -1227,12 +1245,13 @@ impl<'a> Formatter<'a> { /// // We need to remove "-" from the number output. /// let tmp = self.nb.abs().to_string(); /// - /// formatter.pad_integral(self.nb > 0, "Foo ", &tmp) + /// formatter.pad_integral(self.nb >= 0, "Foo ", &tmp) /// } /// } /// /// assert_eq!(&format!("{}", Foo::new(2)), "2"); /// assert_eq!(&format!("{}", Foo::new(-1)), "-1"); + /// assert_eq!(&format!("{}", Foo::new(0)), "0"); /// assert_eq!(&format!("{:#}", Foo::new(-1)), "-Foo 1"); /// assert_eq!(&format!("{:0>#8}", Foo::new(-1)), "00-Foo 1"); /// ``` diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index cc4cf54a2f7..15952c6806f 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -24,8 +24,7 @@ use crate::task::{Context, Poll}; /// `.await` the value. /// /// [`Waker`]: crate::task::Waker -#[cfg_attr(bootstrap, doc(spotlight))] -#[cfg_attr(not(bootstrap), doc(notable_trait))] +#[doc(notable_trait)] #[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] #[lang = "future_trait"] diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index ce5e9936bbd..53e48500e3b 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -98,7 +98,7 @@ where where Self: Sized, F: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { if let Some(ref mut a) = self.a { acc = a.try_fold(acc, &mut f)?; @@ -281,7 +281,7 @@ where where Self: Sized, F: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { if let Some(ref mut b) = self.b { acc = b.try_rfold(acc, &mut f)?; diff --git a/library/core/src/iter/adapters/cloned.rs b/library/core/src/iter/adapters/cloned.rs index 0abdbba2ef1..7efc155175c 100644 --- a/library/core/src/iter/adapters/cloned.rs +++ b/library/core/src/iter/adapters/cloned.rs @@ -46,7 +46,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { self.it.try_fold(init, clone_try_fold(f)) } @@ -82,7 +82,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { self.it.try_rfold(init, clone_try_fold(f)) } diff --git a/library/core/src/iter/adapters/copied.rs b/library/core/src/iter/adapters/copied.rs index 0a5822452a3..def24089275 100644 --- a/library/core/src/iter/adapters/copied.rs +++ b/library/core/src/iter/adapters/copied.rs @@ -50,7 +50,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { self.it.try_fold(init, copy_try_fold(f)) } @@ -98,7 +98,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { self.it.try_rfold(init, copy_try_fold(f)) } diff --git a/library/core/src/iter/adapters/cycle.rs b/library/core/src/iter/adapters/cycle.rs index 6e9a011f819..815e708f9ec 100644 --- a/library/core/src/iter/adapters/cycle.rs +++ b/library/core/src/iter/adapters/cycle.rs @@ -53,7 +53,7 @@ where fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { // fully iterate the current iterator. this is necessary because // `self.iter` may be empty even when `self.orig` isn't diff --git a/library/core/src/iter/adapters/enumerate.rs b/library/core/src/iter/adapters/enumerate.rs index 73cee1df30c..91722a4b62a 100644 --- a/library/core/src/iter/adapters/enumerate.rs +++ b/library/core/src/iter/adapters/enumerate.rs @@ -71,7 +71,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { #[inline] fn enumerate<'a, T, Acc, R>( @@ -150,7 +150,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { // Can safely add and subtract the count, as `ExactSizeIterator` promises // that the number of elements fits into a `usize`. diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs index 0337892b9e8..d5f19f12747 100644 --- a/library/core/src/iter/adapters/filter.rs +++ b/library/core/src/iter/adapters/filter.rs @@ -37,7 +37,7 @@ fn filter_fold<T, Acc>( move |acc, item| if predicate(&item) { fold(acc, item) } else { acc } } -fn filter_try_fold<'a, T, Acc, R: Try<Ok = Acc>>( +fn filter_try_fold<'a, T, Acc, R: Try<Output = Acc>>( predicate: &'a mut impl FnMut(&T) -> bool, mut fold: impl FnMut(Acc, T) -> R + 'a, ) -> impl FnMut(Acc, T) -> R + 'a { @@ -88,7 +88,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.iter.try_fold(init, filter_try_fold(&mut self.predicate, fold)) } @@ -117,7 +117,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.iter.try_rfold(init, filter_try_fold(&mut self.predicate, fold)) } diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs index 0dccf2c533b..01b7be9d52d 100644 --- a/library/core/src/iter/adapters/filter_map.rs +++ b/library/core/src/iter/adapters/filter_map.rs @@ -39,7 +39,7 @@ fn filter_map_fold<T, B, Acc>( } } -fn filter_map_try_fold<'a, T, B, Acc, R: Try<Ok = Acc>>( +fn filter_map_try_fold<'a, T, B, Acc, R: Try<Output = Acc>>( f: &'a mut impl FnMut(T) -> Option<B>, mut fold: impl FnMut(Acc, B) -> R + 'a, ) -> impl FnMut(Acc, T) -> R + 'a { @@ -72,7 +72,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.iter.try_fold(init, filter_map_try_fold(&mut self.f, fold)) } @@ -111,7 +111,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.iter.try_rfold(init, filter_map_try_fold(&mut self.f, fold)) } diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 0114d7af4f4..3315d346596 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -61,7 +61,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.inner.try_fold(init, fold) } @@ -91,7 +91,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.inner.try_rfold(init, fold) } @@ -178,7 +178,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.inner.try_fold(init, fold) } @@ -208,7 +208,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.inner.try_rfold(init, fold) } @@ -293,10 +293,10 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { #[inline] - fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>( + fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>( frontiter: &'a mut Option<T::IntoIter>, fold: &'a mut impl FnMut(Acc, T::Item) -> R, ) -> impl FnMut(Acc, T) -> R + 'a { @@ -382,10 +382,10 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { #[inline] - fn flatten<'a, T: IntoIterator, Acc, R: Try<Ok = Acc>>( + fn flatten<'a, T: IntoIterator, Acc, R: Try<Output = Acc>>( backiter: &'a mut Option<T::IntoIter>, fold: &'a mut impl FnMut(Acc, T::Item) -> R, ) -> impl FnMut(Acc, T) -> R + 'a diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index c01f384dec5..aff48b1b220 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -92,7 +92,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { FuseImpl::try_fold(self, acc, fold) } @@ -148,7 +148,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { FuseImpl::try_rfold(self, acc, fold) } @@ -219,7 +219,7 @@ trait FuseImpl<I> { where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>; + R: Try<Output = Acc>; fn fold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc where Fold: FnMut(Acc, Self::Item) -> Acc; @@ -238,7 +238,7 @@ trait FuseImpl<I> { where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, I: DoubleEndedIterator; fn rfold<Acc, Fold>(self, acc: Acc, fold: Fold) -> Acc where @@ -305,7 +305,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { if let Some(ref mut iter) = self.iter { acc = iter.try_fold(acc, fold)?; @@ -354,7 +354,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, I: DoubleEndedIterator, { if let Some(ref mut iter) = self.iter { @@ -443,7 +443,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { unchecked!(self).try_fold(init, fold) } @@ -485,7 +485,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, I: DoubleEndedIterator, { unchecked!(self).try_rfold(init, fold) diff --git a/library/core/src/iter/adapters/inspect.rs b/library/core/src/iter/adapters/inspect.rs index 88f5ee61b6b..36835d12e56 100644 --- a/library/core/src/iter/adapters/inspect.rs +++ b/library/core/src/iter/adapters/inspect.rs @@ -87,7 +87,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.iter.try_fold(init, inspect_try_fold(&mut self.f, fold)) } @@ -117,7 +117,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.iter.try_rfold(init, inspect_try_fold(&mut self.f, fold)) } diff --git a/library/core/src/iter/adapters/map.rs b/library/core/src/iter/adapters/map.rs index 2a4b7efd5e6..0bf9f4b0327 100644 --- a/library/core/src/iter/adapters/map.rs +++ b/library/core/src/iter/adapters/map.rs @@ -110,7 +110,7 @@ where where Self: Sized, G: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.iter.try_fold(init, map_try_fold(&mut self.f, g)) } @@ -146,7 +146,7 @@ where where Self: Sized, G: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { self.iter.try_rfold(init, map_try_fold(&mut self.f, g)) } diff --git a/library/core/src/iter/adapters/map_while.rs b/library/core/src/iter/adapters/map_while.rs index 26114d53284..8f89e158804 100644 --- a/library/core/src/iter/adapters/map_while.rs +++ b/library/core/src/iter/adapters/map_while.rs @@ -54,7 +54,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { let Self { iter, predicate } = self; iter.try_fold(init, |acc, x| match predicate(x) { diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index 4f69b82ba4c..9fdd4fca04c 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -168,7 +168,7 @@ where fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R where F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { let error = &mut *self.error; self.iter diff --git a/library/core/src/iter/adapters/peekable.rs b/library/core/src/iter/adapters/peekable.rs index 21386e28a96..69bd2996efe 100644 --- a/library/core/src/iter/adapters/peekable.rs +++ b/library/core/src/iter/adapters/peekable.rs @@ -1,5 +1,5 @@ -use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedLen}; -use crate::ops::Try; +use crate::iter::{adapters::SourceIter, FusedIterator, TrustedLen}; +use crate::ops::{ControlFlow, Try}; /// An iterator with a `peek()` that returns an optional reference to the next /// element. @@ -91,7 +91,7 @@ impl<I: Iterator> Iterator for Peekable<I> { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { let acc = match self.peeked.take() { Some(None) => return try { init }, @@ -130,19 +130,42 @@ where } #[inline] + #[cfg(not(bootstrap))] fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { match self.peeked.take() { Some(None) => try { init }, + Some(Some(v)) => match self.iter.try_rfold(init, &mut f).branch() { + ControlFlow::Continue(acc) => f(acc, v), + ControlFlow::Break(r) => { + self.peeked = Some(Some(v)); + R::from_residual(r) + } + }, + None => self.iter.try_rfold(init, f), + } + } + + #[inline] + #[cfg(bootstrap)] + fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>, + { + let _use_the_import: ControlFlow<()>; + match self.peeked.take() { + Some(None) => try { init }, Some(Some(v)) => match self.iter.try_rfold(init, &mut f).into_result() { Ok(acc) => f(acc, v), Err(e) => { self.peeked = Some(Some(v)); - Try::from_error(e) + R::from_error(e) } }, None => self.iter.try_rfold(init, f), @@ -333,6 +356,3 @@ where unsafe { SourceIter::as_inner(&mut self.iter) } } } - -#[unstable(issue = "none", feature = "inplace_iteration")] -unsafe impl<I: InPlaceIterable> InPlaceIterable for Peekable<I> {} diff --git a/library/core/src/iter/adapters/rev.rs b/library/core/src/iter/adapters/rev.rs index 105ed40a3ed..139fb7bbdd9 100644 --- a/library/core/src/iter/adapters/rev.rs +++ b/library/core/src/iter/adapters/rev.rs @@ -51,7 +51,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { self.iter.try_rfold(init, f) } @@ -96,7 +96,7 @@ where where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { self.iter.try_fold(init, f) } diff --git a/library/core/src/iter/adapters/scan.rs b/library/core/src/iter/adapters/scan.rs index 0214899295e..96705b01f66 100644 --- a/library/core/src/iter/adapters/scan.rs +++ b/library/core/src/iter/adapters/scan.rs @@ -56,9 +56,9 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { - fn scan<'a, T, St, B, Acc, R: Try<Ok = Acc>>( + fn scan<'a, T, St, B, Acc, R: Try<Output = Acc>>( state: &'a mut St, f: &'a mut impl FnMut(&mut St, T) -> Option<B>, mut fold: impl FnMut(Acc, B) -> R + 'a, diff --git a/library/core/src/iter/adapters/skip.rs b/library/core/src/iter/adapters/skip.rs index e55c7a6bf5d..c358a6d12b7 100644 --- a/library/core/src/iter/adapters/skip.rs +++ b/library/core/src/iter/adapters/skip.rs @@ -88,7 +88,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { let n = self.n; self.n = 0; @@ -146,9 +146,9 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { - fn check<T, Acc, R: Try<Ok = Acc>>( + fn check<T, Acc, R: Try<Output = Acc>>( mut n: usize, mut fold: impl FnMut(Acc, T) -> R, ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> { diff --git a/library/core/src/iter/adapters/skip_while.rs b/library/core/src/iter/adapters/skip_while.rs index efcb469fc95..93e29edc8df 100644 --- a/library/core/src/iter/adapters/skip_while.rs +++ b/library/core/src/iter/adapters/skip_while.rs @@ -70,7 +70,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { if !self.flag { match self.next() { diff --git a/library/core/src/iter/adapters/step_by.rs b/library/core/src/iter/adapters/step_by.rs index 2ba56eeccba..4252c34a0e0 100644 --- a/library/core/src/iter/adapters/step_by.rs +++ b/library/core/src/iter/adapters/step_by.rs @@ -111,7 +111,7 @@ where fn try_fold<Acc, F, R>(&mut self, mut acc: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { #[inline] fn nth<I: Iterator>(iter: &mut I, step: usize) -> impl FnMut() -> Option<I::Item> + '_ { @@ -187,7 +187,7 @@ where fn try_rfold<Acc, F, R>(&mut self, init: Acc, mut f: F) -> R where F: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { #[inline] fn nth_back<I: DoubleEndedIterator>( diff --git a/library/core/src/iter/adapters/take.rs b/library/core/src/iter/adapters/take.rs index 54a47f1323e..92f82ae2325 100644 --- a/library/core/src/iter/adapters/take.rs +++ b/library/core/src/iter/adapters/take.rs @@ -80,9 +80,9 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { - fn check<'a, T, Acc, R: Try<Ok = Acc>>( + fn check<'a, T, Acc, R: Try<Output = Acc>>( n: &'a mut usize, mut fold: impl FnMut(Acc, T) -> R + 'a, ) -> impl FnMut(Acc, T) -> ControlFlow<R, Acc> + 'a { @@ -178,7 +178,7 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { if self.n == 0 { try { init } diff --git a/library/core/src/iter/adapters/take_while.rs b/library/core/src/iter/adapters/take_while.rs index 746eb41f4c3..93457d20f7c 100644 --- a/library/core/src/iter/adapters/take_while.rs +++ b/library/core/src/iter/adapters/take_while.rs @@ -68,9 +68,9 @@ where where Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, - R: Try<Ok = Acc>, + R: Try<Output = Acc>, { - fn check<'a, T, Acc, R: Try<Ok = Acc>>( + fn check<'a, T, Acc, R: Try<Output = Acc>>( flag: &'a mut bool, p: &'a mut impl FnMut(&T) -> bool, mut fold: impl FnMut(Acc, T) -> R + 'a, diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 2f8f504d8fc..c95324c80ba 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -434,7 +434,7 @@ impl<A: Debug + TrustedRandomAccess, B: Debug + TrustedRandomAccess> ZipFmt<A, B /// called on `self`: /// * `std::clone::Clone::clone()` /// * `std::iter::Iterator::size_hint()` -/// * `std::iter::Iterator::next_back()` +/// * `std::iter::DoubleEndedIterator::next_back()` /// * `std::iter::Iterator::__iterator_get_unchecked()` /// * `std::iter::TrustedRandomAccess::size()` /// diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 2a179f0b1d7..bfb27da505e 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -384,6 +384,8 @@ pub use self::traits::FusedIterator; pub use self::traits::InPlaceIterable; #[unstable(feature = "trusted_len", issue = "37572")] pub use self::traits::TrustedLen; +#[unstable(feature = "trusted_step", issue = "85731")] +pub use self::traits::TrustedStep; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{ DoubleEndedIterator, ExactSizeIterator, Extend, FromIterator, IntoIterator, Product, Sum, diff --git a/library/core/src/iter/range.rs b/library/core/src/iter/range.rs index 5e39e71252f..de5d77e96ee 100644 --- a/library/core/src/iter/range.rs +++ b/library/core/src/iter/range.rs @@ -3,21 +3,23 @@ use crate::convert::TryFrom; use crate::mem; use crate::ops::{self, Try}; -use super::{FusedIterator, TrustedLen, TrustedRandomAccess}; +use super::{FusedIterator, TrustedLen, TrustedRandomAccess, TrustedStep}; + +// Safety: All invariants are upheld. +macro_rules! unsafe_impl_trusted_step { + ($($type:ty)*) => {$( + #[unstable(feature = "trusted_step", issue = "85731")] + unsafe impl TrustedStep for $type {} + )*}; +} +unsafe_impl_trusted_step![char i8 i16 i32 i64 i128 isize u8 u16 u32 u64 u128 usize]; /// Objects that have a notion of *successor* and *predecessor* operations. /// /// The *successor* operation moves towards values that compare greater. /// The *predecessor* operation moves towards values that compare lesser. -/// -/// # Safety -/// -/// This trait is `unsafe` because its implementation must be correct for -/// the safety of `unsafe trait TrustedLen` implementations, and the results -/// of using this trait can otherwise be trusted by `unsafe` code to be correct -/// and fulfill the listed obligations. #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] -pub unsafe trait Step: Clone + PartialOrd + Sized { +pub trait Step: Clone + PartialOrd + Sized { /// Returns the number of *successor* steps required to get from `start` to `end`. /// /// Returns `None` if the number of steps would overflow `usize` @@ -55,7 +57,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// /// * `Step::forward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::forward_checked(&x, 1))` /// * Corollary: `Step::forward_checked(&a, 0) == Some(a)` - #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")] fn forward_checked(start: Self, count: usize) -> Option<Self>; /// Returns the value that would be obtained by taking the *successor* @@ -81,7 +82,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// * Corollary: `Step::forward(a, 0) == a` /// * `Step::forward(a, n) >= a` /// * `Step::backward(Step::forward(a, n), n) == a` - #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")] fn forward(start: Self, count: usize) -> Self { Step::forward_checked(start, count).expect("overflow in `Step::forward`") } @@ -106,7 +106,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// For any `a` and `n`, where no overflow occurs: /// /// * `Step::forward_unchecked(a, n)` is equivalent to `Step::forward(a, n)` - #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")] unsafe fn forward_unchecked(start: Self, count: usize) -> Self { Step::forward(start, count) } @@ -127,7 +126,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// /// * `Step::backward_checked(a, n) == (0..n).try_fold(a, |x, _| Step::backward_checked(&x, 1))` /// * Corollary: `Step::backward_checked(&a, 0) == Some(a)` - #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")] fn backward_checked(start: Self, count: usize) -> Option<Self>; /// Returns the value that would be obtained by taking the *predecessor* @@ -153,7 +151,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// * Corollary: `Step::backward(a, 0) == a` /// * `Step::backward(a, n) <= a` /// * `Step::forward(Step::backward(a, n), n) == a` - #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")] fn backward(start: Self, count: usize) -> Self { Step::backward_checked(start, count).expect("overflow in `Step::backward`") } @@ -178,7 +175,6 @@ pub unsafe trait Step: Clone + PartialOrd + Sized { /// For any `a` and `n`, where no overflow occurs: /// /// * `Step::backward_unchecked(a, n)` is equivalent to `Step::backward(a, n)` - #[unstable(feature = "step_trait_ext", reason = "recently added", issue = "42168")] unsafe fn backward_unchecked(start: Self, count: usize) -> Self { Step::backward(start, count) } @@ -237,7 +233,7 @@ macro_rules! step_integer_impls { $( #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - unsafe impl Step for $u_narrower { + impl Step for $u_narrower { step_identical_methods!(); #[inline] @@ -269,7 +265,7 @@ macro_rules! step_integer_impls { #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - unsafe impl Step for $i_narrower { + impl Step for $i_narrower { step_identical_methods!(); #[inline] @@ -333,7 +329,7 @@ macro_rules! step_integer_impls { $( #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - unsafe impl Step for $u_wider { + impl Step for $u_wider { step_identical_methods!(); #[inline] @@ -358,7 +354,7 @@ macro_rules! step_integer_impls { #[allow(unreachable_patterns)] #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] - unsafe impl Step for $i_wider { + impl Step for $i_wider { step_identical_methods!(); #[inline] @@ -408,7 +404,7 @@ step_integer_impls! { } #[unstable(feature = "step_trait", reason = "recently redesigned", issue = "42168")] -unsafe impl Step for char { +impl Step for char { #[inline] fn steps_between(&start: &char, &end: &char) -> Option<usize> { let start = start as u32; @@ -512,15 +508,27 @@ macro_rules! range_incl_exact_iter_impl { )*) } -#[stable(feature = "rust1", since = "1.0.0")] -impl<A: Step> Iterator for ops::Range<A> { +/// Specialization implementations for `Range`. +trait RangeIteratorImpl { + type Item; + + // Iterator + fn spec_next(&mut self) -> Option<Self::Item>; + fn spec_nth(&mut self, n: usize) -> Option<Self::Item>; + + // DoubleEndedIterator + fn spec_next_back(&mut self) -> Option<Self::Item>; + fn spec_nth_back(&mut self, n: usize) -> Option<Self::Item>; +} + +impl<A: Step> RangeIteratorImpl for ops::Range<A> { type Item = A; #[inline] - fn next(&mut self) -> Option<A> { + default fn spec_next(&mut self) -> Option<A> { if self.start < self.end { - // SAFETY: just checked precondition - let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; + let n = + Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld"); Some(mem::replace(&mut self.start, n)) } else { None @@ -528,17 +536,59 @@ impl<A: Step> Iterator for ops::Range<A> { } #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { + default fn spec_nth(&mut self, n: usize) -> Option<A> { + if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) { + if plus_n < self.end { + self.start = + Step::forward_checked(plus_n.clone(), 1).expect("`Step` invariants not upheld"); + return Some(plus_n); + } + } + + self.start = self.end.clone(); + None + } + + #[inline] + default fn spec_next_back(&mut self) -> Option<A> { if self.start < self.end { - let hint = Step::steps_between(&self.start, &self.end); - (hint.unwrap_or(usize::MAX), hint) + self.end = + Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld"); + Some(self.end.clone()) } else { - (0, Some(0)) + None } } #[inline] - fn nth(&mut self, n: usize) -> Option<A> { + default fn spec_nth_back(&mut self, n: usize) -> Option<A> { + if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) { + if minus_n > self.start { + self.end = + Step::backward_checked(minus_n, 1).expect("`Step` invariants not upheld"); + return Some(self.end.clone()); + } + } + + self.end = self.start.clone(); + None + } +} + +impl<T: TrustedStep> RangeIteratorImpl for ops::Range<T> { + #[inline] + fn spec_next(&mut self) -> Option<T> { + if self.start < self.end { + // SAFETY: just checked precondition + let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; + Some(mem::replace(&mut self.start, n)) + } else { + None + } + } + + #[inline] + fn spec_nth(&mut self, n: usize) -> Option<T> { if let Some(plus_n) = Step::forward_checked(self.start.clone(), n) { if plus_n < self.end { // SAFETY: just checked precondition @@ -552,6 +602,56 @@ impl<A: Step> Iterator for ops::Range<A> { } #[inline] + fn spec_next_back(&mut self) -> Option<T> { + if self.start < self.end { + // SAFETY: just checked precondition + self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; + Some(self.end.clone()) + } else { + None + } + } + + #[inline] + fn spec_nth_back(&mut self, n: usize) -> Option<T> { + if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) { + if minus_n > self.start { + // SAFETY: just checked precondition + self.end = unsafe { Step::backward_unchecked(minus_n, 1) }; + return Some(self.end.clone()); + } + } + + self.end = self.start.clone(); + None + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<A: Step> Iterator for ops::Range<A> { + type Item = A; + + #[inline] + fn next(&mut self) -> Option<A> { + self.spec_next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option<usize>) { + if self.start < self.end { + let hint = Step::steps_between(&self.start, &self.end); + (hint.unwrap_or(usize::MAX), hint) + } else { + (0, Some(0)) + } + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<A> { + self.spec_nth(n) + } + + #[inline] fn last(mut self) -> Option<A> { self.next_back() } @@ -631,32 +731,36 @@ range_incl_exact_iter_impl! { impl<A: Step> DoubleEndedIterator for ops::Range<A> { #[inline] fn next_back(&mut self) -> Option<A> { - if self.start < self.end { - // SAFETY: just checked precondition - self.end = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; - Some(self.end.clone()) - } else { - None - } + self.spec_next_back() } #[inline] fn nth_back(&mut self, n: usize) -> Option<A> { - if let Some(minus_n) = Step::backward_checked(self.end.clone(), n) { - if minus_n > self.start { - // SAFETY: just checked precondition - self.end = unsafe { Step::backward_unchecked(minus_n, 1) }; - return Some(self.end.clone()); - } - } - - self.end = self.start.clone(); - None + self.spec_nth_back(n) } } +// Safety: +// The following invariants for `Step::steps_between` exist: +// +// > * `steps_between(&a, &b) == Some(n)` only if `a <= b` +// > * Note that `a <= b` does _not_ imply `steps_between(&a, &b) != None`; +// > this is the case when it would require more than `usize::MAX` steps to +// > get to `b` +// > * `steps_between(&a, &b) == None` if `a > b` +// +// The first invariant is what is generally required for `TrustedLen` to be +// sound. The note addendum satisfies an additional `TrustedLen` invariant. +// +// > The upper bound must only be `None` if the actual iterator length is larger +// > than `usize::MAX` +// +// The second invariant logically follows the first so long as the `PartialOrd` +// implementation is correct; regardless it is explicitly stated. If `a < b` +// then `(0, Some(0))` is returned by `ops::Range<A: Step>::size_hint`. As such +// the second invariant is upheld. #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<A: Step> TrustedLen for ops::Range<A> {} +unsafe impl<A: TrustedStep> TrustedLen for ops::Range<A> {} #[stable(feature = "fused", since = "1.26.0")] impl<A: Step> FusedIterator for ops::Range<A> {} @@ -684,18 +788,130 @@ impl<A: Step> Iterator for ops::RangeFrom<A> { } } +// Safety: See above implementation for `ops::Range<A>` +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl<A: TrustedStep> TrustedLen for ops::RangeFrom<A> {} + #[stable(feature = "fused", since = "1.26.0")] impl<A: Step> FusedIterator for ops::RangeFrom<A> {} -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<A: Step> TrustedLen for ops::RangeFrom<A> {} +trait RangeInclusiveIteratorImpl { + type Item; -#[stable(feature = "inclusive_range", since = "1.26.0")] -impl<A: Step> Iterator for ops::RangeInclusive<A> { + // Iterator + fn spec_next(&mut self) -> Option<Self::Item>; + fn spec_try_fold<B, F, R>(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>; + + // DoubleEndedIterator + fn spec_next_back(&mut self) -> Option<Self::Item>; + fn spec_try_rfold<B, F, R>(&mut self, init: B, f: F) -> R + where + Self: Sized, + F: FnMut(B, Self::Item) -> R, + R: Try<Output = B>; +} + +impl<A: Step> RangeInclusiveIteratorImpl for ops::RangeInclusive<A> { type Item = A; #[inline] - fn next(&mut self) -> Option<A> { + default fn spec_next(&mut self) -> Option<A> { + if self.is_empty() { + return None; + } + let is_iterating = self.start < self.end; + Some(if is_iterating { + let n = + Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld"); + mem::replace(&mut self.start, n) + } else { + self.exhausted = true; + self.start.clone() + }) + } + + #[inline] + default fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, A) -> R, + R: Try<Output = B>, + { + if self.is_empty() { + return try { init }; + } + + let mut accum = init; + + while self.start < self.end { + let n = + Step::forward_checked(self.start.clone(), 1).expect("`Step` invariants not upheld"); + let n = mem::replace(&mut self.start, n); + accum = f(accum, n)?; + } + + self.exhausted = true; + + if self.start == self.end { + accum = f(accum, self.start.clone())?; + } + + try { accum } + } + + #[inline] + default fn spec_next_back(&mut self) -> Option<A> { + if self.is_empty() { + return None; + } + let is_iterating = self.start < self.end; + Some(if is_iterating { + let n = + Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld"); + mem::replace(&mut self.end, n) + } else { + self.exhausted = true; + self.end.clone() + }) + } + + #[inline] + default fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, A) -> R, + R: Try<Output = B>, + { + if self.is_empty() { + return try { init }; + } + + let mut accum = init; + + while self.start < self.end { + let n = + Step::backward_checked(self.end.clone(), 1).expect("`Step` invariants not upheld"); + let n = mem::replace(&mut self.end, n); + accum = f(accum, n)?; + } + + self.exhausted = true; + + if self.start == self.end { + accum = f(accum, self.start.clone())?; + } + + try { accum } + } +} + +impl<T: TrustedStep> RangeInclusiveIteratorImpl for ops::RangeInclusive<T> { + #[inline] + fn spec_next(&mut self) -> Option<T> { if self.is_empty() { return None; } @@ -711,6 +927,90 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> { } #[inline] + fn spec_try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, T) -> R, + R: Try<Output = B>, + { + if self.is_empty() { + return try { init }; + } + + let mut accum = init; + + while self.start < self.end { + // SAFETY: just checked precondition + let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; + let n = mem::replace(&mut self.start, n); + accum = f(accum, n)?; + } + + self.exhausted = true; + + if self.start == self.end { + accum = f(accum, self.start.clone())?; + } + + try { accum } + } + + #[inline] + fn spec_next_back(&mut self) -> Option<T> { + if self.is_empty() { + return None; + } + let is_iterating = self.start < self.end; + Some(if is_iterating { + // SAFETY: just checked precondition + let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; + mem::replace(&mut self.end, n) + } else { + self.exhausted = true; + self.end.clone() + }) + } + + #[inline] + fn spec_try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R + where + Self: Sized, + F: FnMut(B, T) -> R, + R: Try<Output = B>, + { + if self.is_empty() { + return try { init }; + } + + let mut accum = init; + + while self.start < self.end { + // SAFETY: just checked precondition + let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; + let n = mem::replace(&mut self.end, n); + accum = f(accum, n)?; + } + + self.exhausted = true; + + if self.start == self.end { + accum = f(accum, self.start.clone())?; + } + + try { accum } + } +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +impl<A: Step> Iterator for ops::RangeInclusive<A> { + type Item = A; + + #[inline] + fn next(&mut self) -> Option<A> { + self.spec_next() + } + + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { if self.is_empty() { return (0, Some(0)); @@ -751,32 +1051,13 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> { } #[inline] - fn try_fold<B, F, R>(&mut self, init: B, mut f: F) -> R + fn try_fold<B, F, R>(&mut self, init: B, f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { - if self.is_empty() { - return try { init }; - } - - let mut accum = init; - - while self.start < self.end { - // SAFETY: just checked precondition - let n = unsafe { Step::forward_unchecked(self.start.clone(), 1) }; - let n = mem::replace(&mut self.start, n); - accum = f(accum, n)?; - } - - self.exhausted = true; - - if self.start == self.end { - accum = f(accum, self.start.clone())?; - } - - try { accum } + self.spec_try_fold(init, f) } #[inline] @@ -813,18 +1094,7 @@ impl<A: Step> Iterator for ops::RangeInclusive<A> { impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> { #[inline] fn next_back(&mut self) -> Option<A> { - if self.is_empty() { - return None; - } - let is_iterating = self.start < self.end; - Some(if is_iterating { - // SAFETY: just checked precondition - let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; - mem::replace(&mut self.end, n) - } else { - self.exhausted = true; - self.end.clone() - }) + self.spec_next_back() } #[inline] @@ -856,32 +1126,13 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> { } #[inline] - fn try_rfold<B, F, R>(&mut self, init: B, mut f: F) -> R + fn try_rfold<B, F, R>(&mut self, init: B, f: F) -> R where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { - if self.is_empty() { - return try { init }; - } - - let mut accum = init; - - while self.start < self.end { - // SAFETY: just checked precondition - let n = unsafe { Step::backward_unchecked(self.end.clone(), 1) }; - let n = mem::replace(&mut self.end, n); - accum = f(accum, n)?; - } - - self.exhausted = true; - - if self.start == self.end { - accum = f(accum, self.start.clone())?; - } - - try { accum } + self.spec_try_rfold(init, f) } #[inline] @@ -899,8 +1150,9 @@ impl<A: Step> DoubleEndedIterator for ops::RangeInclusive<A> { } } +// Safety: See above implementation for `ops::Range<A>` #[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl<A: Step> TrustedLen for ops::RangeInclusive<A> {} +unsafe impl<A: TrustedStep> TrustedLen for ops::RangeInclusive<A> {} #[stable(feature = "fused", since = "1.26.0")] impl<A: Step> FusedIterator for ops::RangeInclusive<A> {} diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs index d1f2879235f..a9478041c69 100644 --- a/library/core/src/iter/sources/repeat.rs +++ b/library/core/src/iter/sources/repeat.rs @@ -72,10 +72,32 @@ impl<A: Clone> Iterator for Repeat<A> { fn next(&mut self) -> Option<A> { Some(self.element.clone()) } + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { (usize::MAX, None) } + + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + // Advancing an infinite iterator of a single element is a no-op. + let _ = n; + Ok(()) + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<A> { + let _ = n; + Some(self.element.clone()) + } + + fn last(self) -> Option<A> { + loop {} + } + + fn count(self) -> usize { + loop {} + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -84,6 +106,19 @@ impl<A: Clone> DoubleEndedIterator for Repeat<A> { fn next_back(&mut self) -> Option<A> { Some(self.element.clone()) } + + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + // Advancing an infinite iterator of a single element is a no-op. + let _ = n; + Ok(()) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<A> { + let _ = n; + Some(self.element.clone()) + } } #[stable(feature = "fused", since = "1.26.0")] diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 13a2e24cadd..e2a407509b1 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -198,7 +198,7 @@ pub trait FromIterator<A>: Sized { /// } /// ``` #[rustc_diagnostic_item = "IntoIterator"] -#[cfg_attr(not(bootstrap), rustc_skip_array_during_method_dispatch)] +#[rustc_skip_array_during_method_dispatch] #[stable(feature = "rust1", since = "1.0.0")] pub trait IntoIterator { /// The type of the elements being iterated over. diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 6f8cb6b5a65..c302502b3b7 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -218,7 +218,7 @@ pub trait DoubleEndedIterator: Iterator { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { let mut accum = init; while let Some(x) = self.next_back() { diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index da9e5fde7cc..96b924f6e2a 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -26,40 +26,6 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( - _Self = "[std::ops::Range<Idx>; 1]", - label = "if you meant to iterate between two values, remove the square brackets", - note = "`[start..end]` is an array of one `Range`; you might have meant to have a `Range` \ - without the brackets: `start..end`" - ), - on( - _Self = "[std::ops::RangeFrom<Idx>; 1]", - label = "if you meant to iterate from a value onwards, remove the square brackets", - note = "`[start..]` is an array of one `RangeFrom`; you might have meant to have a \ - `RangeFrom` without the brackets: `start..`, keeping in mind that iterating over an \ - unbounded iterator will run forever unless you `break` or `return` from within the \ - loop" - ), - on( - _Self = "[std::ops::RangeTo<Idx>; 1]", - label = "if you meant to iterate until a value, remove the square brackets and add a \ - starting value", - note = "`[..end]` is an array of one `RangeTo`; you might have meant to have a bounded \ - `Range` without the brackets: `0..end`" - ), - on( - _Self = "[std::ops::RangeInclusive<Idx>; 1]", - label = "if you meant to iterate between two values, remove the square brackets", - note = "`[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a \ - `RangeInclusive` without the brackets: `start..=end`" - ), - on( - _Self = "[std::ops::RangeToInclusive<Idx>; 1]", - label = "if you meant to iterate until a value (including it), remove the square brackets \ - and add a starting value", - note = "`[..=end]` is an array of one `RangeToInclusive`; you might have meant to have a \ - bounded `RangeInclusive` without the brackets: `0..=end`" - ), - on( _Self = "std::ops::RangeTo<Idx>", label = "if you meant to iterate until a value, add a starting value", note = "`..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a \ @@ -80,11 +46,6 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} label = "`{Self}` is not an iterator; try calling `.chars()` or `.bytes()`" ), on( - _Self = "[]", - label = "arrays do not yet implement `IntoIterator`; try using `std::array::IntoIter::new(arr)`", - note = "see <https://github.com/rust-lang/rust/pull/65819> for more details" - ), - on( _Self = "{integral}", note = "if you want to iterate between `start` until a value `end`, use the exclusive range \ syntax `start..end` or the inclusive range syntax `start..=end`" @@ -92,8 +53,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {} label = "`{Self}` is not an iterator", message = "`{Self}` is not an iterator" )] -#[cfg_attr(bootstrap, doc(spotlight))] -#[cfg_attr(not(bootstrap), doc(notable_trait))] +#[doc(notable_trait)] #[rustc_diagnostic_item = "Iterator"] #[must_use = "iterators are lazy and do nothing unless consumed"] pub trait Iterator { @@ -1849,6 +1809,12 @@ pub trait Iterator { /// /// The relative order of partitioned items is not maintained. /// + /// # Current implementation + /// Current algorithms tries finding the first element for which the predicate evaluates + /// to false, and the last element for which it evaluates to true and repeatedly swaps them. + /// + /// Time Complexity: *O*(*N*) + /// /// See also [`is_partitioned()`] and [`partition()`]. /// /// [`is_partitioned()`]: Iterator::is_partitioned @@ -1999,7 +1965,7 @@ pub trait Iterator { where Self: Sized, F: FnMut(B, Self::Item) -> R, - R: Try<Ok = B>, + R: Try<Output = B>, { let mut accum = init; while let Some(x) = self.next() { @@ -2041,7 +2007,7 @@ pub trait Iterator { where Self: Sized, F: FnMut(Self::Item) -> R, - R: Try<Ok = ()>, + R: Try<Output = ()>, { #[inline] fn call<T, R>(mut f: impl FnMut(T) -> R) -> impl FnMut((), T) -> R { @@ -2412,17 +2378,48 @@ pub trait Iterator { /// ``` #[inline] #[unstable(feature = "try_find", reason = "new API", issue = "63178")] + #[cfg(not(bootstrap))] + fn try_find<F, R, E>(&mut self, f: F) -> Result<Option<Self::Item>, E> + where + Self: Sized, + F: FnMut(&Self::Item) -> R, + R: Try<Output = bool>, + // FIXME: This bound is rather strange, but means minimal breakage on nightly. + // See #85115 for the issue tracking a holistic solution for this and try_map. + R: crate::ops::TryV2<Residual = Result<crate::convert::Infallible, E>>, + { + #[inline] + fn check<F, T, R, E>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, E>> + where + F: FnMut(&T) -> R, + R: Try<Output = bool>, + R: crate::ops::TryV2<Residual = Result<crate::convert::Infallible, E>>, + { + move |(), x| match f(&x).branch() { + ControlFlow::Continue(false) => ControlFlow::CONTINUE, + ControlFlow::Continue(true) => ControlFlow::Break(Ok(x)), + ControlFlow::Break(Err(x)) => ControlFlow::Break(Err(x)), + } + } + + self.try_fold((), check(f)).break_value().transpose() + } + + /// We're bootstrapping. + #[inline] + #[unstable(feature = "try_find", reason = "new API", issue = "63178")] + #[cfg(bootstrap)] fn try_find<F, R>(&mut self, f: F) -> Result<Option<Self::Item>, R::Error> where Self: Sized, F: FnMut(&Self::Item) -> R, - R: Try<Ok = bool>, + R: Try<Output = bool>, { #[inline] fn check<F, T, R>(mut f: F) -> impl FnMut((), T) -> ControlFlow<Result<T, R::Error>> where F: FnMut(&T) -> R, - R: Try<Ok = bool>, + R: Try<Output = bool>, { move |(), x| match f(&x).into_result() { Ok(false) => ControlFlow::CONTINUE, @@ -2571,6 +2568,18 @@ pub trait Iterator { /// If several elements are equally maximum, the last element is /// returned. If the iterator is empty, [`None`] is returned. /// + /// Note that [`f32`]/[`f64`] doesn't implement [`Ord`] due to NaN being + /// incomparable. You can work around this by using [`Iterator::reduce`]: + /// ``` + /// assert_eq!( + /// vec![2.4, f32::NAN, 1.3] + /// .into_iter() + /// .reduce(f32::max) + /// .unwrap(), + /// 2.4 + /// ); + /// ``` + /// /// # Examples /// /// Basic usage: @@ -2594,8 +2603,20 @@ pub trait Iterator { /// Returns the minimum element of an iterator. /// - /// If several elements are equally minimum, the first element is - /// returned. If the iterator is empty, [`None`] is returned. + /// If several elements are equally minimum, the first element is returned. + /// If the iterator is empty, [`None`] is returned. + /// + /// Note that [`f32`]/[`f64`] doesn't implement [`Ord`] due to NaN being + /// incomparable. You can work around this by using [`Iterator::reduce`]: + /// ``` + /// assert_eq!( + /// vec![2.4, f32::NAN, 1.3] + /// .into_iter() + /// .reduce(f32::min) + /// .unwrap(), + /// 1.3 + /// ); + /// ``` /// /// # Examples /// diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index 22b5ffdf886..ebf37f97bc6 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -1,3 +1,5 @@ +use crate::iter::Step; + /// An iterator that always continues to yield `None` when exhausted. /// /// Calling next on a fused iterator that has returned `None` once is guaranteed @@ -55,3 +57,18 @@ unsafe impl<I: TrustedLen + ?Sized> TrustedLen for &mut I {} #[unstable(issue = "none", feature = "inplace_iteration")] #[doc(hidden)] pub unsafe trait InPlaceIterable: Iterator {} + +/// A type that upholds all invariants of [`Step`]. +/// +/// The invariants of [`Step::steps_between()`] are a superset of the invariants +/// of [`TrustedLen`]. As such, [`TrustedLen`] is implemented for all range +/// types with the same generic type argument. +/// +/// # Safety +/// +/// The implementation of [`Step`] for the given type must guarantee all +/// invariants of all methods are upheld. See the [`Step`] trait's documentation +/// for details. Consumers are free to rely on the invariants in unsafe code. +#[unstable(feature = "trusted_step", issue = "85731")] +#[rustc_specialization_trait] +pub unsafe trait TrustedStep: Step {} diff --git a/library/core/src/iter/traits/mod.rs b/library/core/src/iter/traits/mod.rs index 880f8d831fd..ffd745a46b1 100644 --- a/library/core/src/iter/traits/mod.rs +++ b/library/core/src/iter/traits/mod.rs @@ -13,5 +13,7 @@ pub use self::exact_size::ExactSizeIterator; pub use self::iterator::Iterator; #[unstable(issue = "none", feature = "inplace_iteration")] pub use self::marker::InPlaceIterable; +#[unstable(feature = "trusted_step", issue = "85731")] +pub use self::marker::TrustedStep; #[stable(feature = "rust1", since = "1.0.0")] pub use self::marker::{FusedIterator, TrustedLen}; diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 6a4f2d5a544..a023edaca9e 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -82,12 +82,12 @@ #![feature(const_refs_to_cell)] #![feature(const_panic)] #![feature(const_pin)] -#![cfg_attr(bootstrap, feature(const_fn))] #![feature(const_fn_union)] #![feature(const_impl_trait)] #![feature(const_fn_floating_point_arithmetic)] #![feature(const_fn_fn_ptr_basics)] -#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))] +#![feature(const_fn_trait_bound)] +#![cfg_attr(bootstrap, feature(const_fn))] #![feature(const_option)] #![feature(const_precise_live_drops)] #![feature(const_ptr_offset)] @@ -110,10 +110,9 @@ #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] -#![cfg_attr(bootstrap, feature(doc_spotlight))] -#![cfg_attr(not(bootstrap), feature(doc_notable_trait))] +#![feature(doc_notable_trait)] #![feature(duration_consts_2)] -#![feature(extended_key_value_attributes)] +#![cfg_attr(bootstrap, feature(extended_key_value_attributes))] #![feature(extern_types)] #![feature(fundamental)] #![feature(intra_doc_pointers)] @@ -127,7 +126,6 @@ #![feature(exhaustive_patterns)] #![feature(no_core)] #![feature(auto_traits)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(prelude_import)] #![feature(ptr_metadata)] #![feature(repr_simd, platform_intrinsics)] @@ -167,9 +165,10 @@ #![feature(const_caller_location)] #![feature(slice_ptr_get)] #![feature(no_niche)] // rust-lang/rust#68303 -#![cfg_attr(not(bootstrap), feature(no_coverage))] // rust-lang/rust#84605 +#![feature(no_coverage)] // rust-lang/rust#84605 #![feature(int_error_matching)] #![deny(unsafe_op_in_unsafe_fn)] +#![deny(or_patterns_back_compat)] // allow using `core::` in intra-doc links #[allow(unused_extern_crates)] @@ -304,8 +303,7 @@ pub mod primitive; unused_imports, unsafe_op_in_unsafe_fn )] -#[cfg_attr(bootstrap, allow(rustdoc::non_autolinks))] -#[cfg_attr(not(bootstrap), allow(rustdoc::bare_urls))] +#[allow(rustdoc::bare_urls)] // FIXME: This annotation should be moved into rust-lang/stdarch after clashing_extern_declarations is // merged. It currently cannot because bootstrap fails as the lint hasn't been defined yet. #[allow(clashing_extern_declarations)] diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index b46a7aa138c..7eb65483b99 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -138,7 +138,7 @@ macro_rules! assert_ne { #[unstable(feature = "assert_matches", issue = "82775")] #[allow_internal_unstable(core_panic)] macro_rules! assert_matches { - ($left:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => ({ + ($left:expr, $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => ({ match $left { $( $pattern )|+ $( if $guard )? => {} ref left_val => { @@ -150,7 +150,7 @@ macro_rules! assert_matches { } } }); - ($left:expr, $( $pattern:pat )|+ $( if $guard: expr )?, $($arg:tt)+) => ({ + ($left:expr, $( $pattern:pat_param )|+ $( if $guard: expr )?, $($arg:tt)+) => ({ match $left { $( $pattern )|+ $( if $guard )? => {} ref left_val => { @@ -315,7 +315,7 @@ macro_rules! debug_assert_matches { #[macro_export] #[stable(feature = "matches_macro", since = "1.42.0")] macro_rules! matches { - ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => { + ($expression:expr, $( $pattern:pat_param )|+ $( if $guard: expr )? $(,)?) => { match $expression { $( $pattern )|+ $( if $guard )? => true, _ => false @@ -595,7 +595,7 @@ macro_rules! unreachable { /// Indicates unimplemented code by panicking with a message of "not implemented". /// /// This allows your code to type-check, which is useful if you are prototyping or -/// implementing a trait that requires multiple methods which you don't plan of using all of. +/// implementing a trait that requires multiple methods which you don't plan to use all of. /// /// The difference between `unimplemented!` and [`todo!`] is that while `todo!` /// conveys an intent of implementing the functionality later and the message is "not yet diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index d86939454be..5b99f6954e6 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -44,7 +44,7 @@ use crate::ptr; /// [`MaybeUninit<T>`]: crate::mem::MaybeUninit #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] -#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[derive(Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[repr(transparent)] pub struct ManuallyDrop<T: ?Sized> { value: T, @@ -160,3 +160,16 @@ impl<T: ?Sized> DerefMut for ManuallyDrop<T> { &mut self.value } } + +#[stable(feature = "manually_drop", since = "1.20.0")] +impl<T: Clone> Clone for ManuallyDrop<T> { + #[inline] + fn clone(&self) -> ManuallyDrop<T> { + ManuallyDrop { value: self.value.clone() } + } + + #[inline] + fn clone_from(&mut self, other: &Self) { + self.value.clone_from(&other.value) + } +} diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 0d6d919d998..c47a2e8b05c 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -727,8 +727,8 @@ impl f32 { /// /// This is currently identical to `transmute::<f32, u32>(self)` on all platforms. /// - /// See `from_bits` for some discussion of the portability of this operation - /// (there are almost no issues). + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). /// /// Note that this function is distinct from `as` casting, which attempts to /// preserve the *numeric* value, and not the bitwise value. @@ -854,35 +854,6 @@ impl f32 { self.to_bits().to_ne_bytes() } - /// Return the memory representation of this floating point number as a byte array in - /// native byte order. - /// - /// [`to_ne_bytes`] should be preferred over this whenever possible. - /// - /// [`to_ne_bytes`]: f32::to_ne_bytes - /// - /// # Examples - /// - /// ``` - /// #![feature(num_as_ne_bytes)] - /// let num = 12.5f32; - /// let bytes = num.as_ne_bytes(); - /// assert_eq!( - /// bytes, - /// if cfg!(target_endian = "big") { - /// &[0x41, 0x48, 0x00, 0x00] - /// } else { - /// &[0x00, 0x00, 0x48, 0x41] - /// } - /// ); - /// ``` - #[unstable(feature = "num_as_ne_bytes", issue = "76976")] - #[inline] - pub fn as_ne_bytes(&self) -> &[u8; 4] { - // SAFETY: `f32` is a plain old datatype so we can always transmute to it - unsafe { &*(self as *const Self as *const _) } - } - /// Create a floating point value from its representation as a byte array in big endian. /// /// # Examples diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 42214e7b50d..cfcc08b9add 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -741,8 +741,8 @@ impl f64 { /// /// This is currently identical to `transmute::<f64, u64>(self)` on all platforms. /// - /// See `from_bits` for some discussion of the portability of this operation - /// (there are almost no issues). + /// See [`from_bits`](Self::from_bits) for some discussion of the + /// portability of this operation (there are almost no issues). /// /// Note that this function is distinct from `as` casting, which attempts to /// preserve the *numeric* value, and not the bitwise value. @@ -868,35 +868,6 @@ impl f64 { self.to_bits().to_ne_bytes() } - /// Return the memory representation of this floating point number as a byte array in - /// native byte order. - /// - /// [`to_ne_bytes`] should be preferred over this whenever possible. - /// - /// [`to_ne_bytes`]: f64::to_ne_bytes - /// - /// # Examples - /// - /// ``` - /// #![feature(num_as_ne_bytes)] - /// let num = 12.5f64; - /// let bytes = num.as_ne_bytes(); - /// assert_eq!( - /// bytes, - /// if cfg!(target_endian = "big") { - /// &[0x40, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] - /// } else { - /// &[0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x40] - /// } - /// ); - /// ``` - #[unstable(feature = "num_as_ne_bytes", issue = "76976")] - #[inline] - pub fn as_ne_bytes(&self) -> &[u8; 8] { - // SAFETY: `f64` is a plain old datatype so we can always transmute to it - unsafe { &*(self as *const Self as *const _) } - } - /// Create a floating point value from its representation as a byte array in big endian. /// /// # Examples diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 47b2b30563c..a0efe681285 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -407,8 +407,15 @@ macro_rules! int_impl { } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow - /// cannot occur. This results in undefined behavior when - #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")] + /// cannot occur. + /// + /// # Safety + /// + /// This results in undefined behavior when + #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")] + /// i.e. when [`checked_add`] would return `None`. + /// + #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")] #[unstable( feature = "unchecked_math", reason = "niche optimization path", @@ -446,8 +453,15 @@ macro_rules! int_impl { } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow - /// cannot occur. This results in undefined behavior when - #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")] + /// cannot occur. + /// + /// # Safety + /// + /// This results in undefined behavior when + #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")] + /// i.e. when [`checked_sub`] would return `None`. + /// + #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")] #[unstable( feature = "unchecked_math", reason = "niche optimization path", @@ -485,8 +499,15 @@ macro_rules! int_impl { } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow - /// cannot occur. This results in undefined behavior when - #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")] + /// cannot occur. + /// + /// # Safety + /// + /// This results in undefined behavior when + #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")] + /// i.e. when [`checked_mul`] would return `None`. + /// + #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")] #[unstable( feature = "unchecked_math", reason = "niche optimization path", @@ -645,6 +666,31 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Unchecked shift left. Computes `self << rhs`, assuming that + /// `rhs` is less than the number of bits in `self`. + /// + /// # Safety + /// + /// This results in undefined behavior if `rhs` is larger than + /// or equal to the number of bits in `self`, + /// i.e. when [`checked_shl`] would return `None`. + /// + #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")] + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "85122", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] + #[inline(always)] + pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_shl`. + unsafe { intrinsics::unchecked_shl(self, rhs) } + } + /// Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is /// larger than or equal to the number of bits in `self`. /// @@ -666,6 +712,31 @@ macro_rules! int_impl { if unlikely!(b) {None} else {Some(a)} } + /// Unchecked shift right. Computes `self >> rhs`, assuming that + /// `rhs` is less than the number of bits in `self`. + /// + /// # Safety + /// + /// This results in undefined behavior if `rhs` is larger than + /// or equal to the number of bits in `self`, + /// i.e. when [`checked_shr`] would return `None`. + /// + #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")] + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "85122", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] + #[inline(always)] + pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_shr`. + unsafe { intrinsics::unchecked_shr(self, rhs) } + } + /// Checked absolute value. Computes `self.abs()`, returning `None` if /// `self == MIN`. /// @@ -1842,36 +1913,6 @@ macro_rules! int_impl { unsafe { mem::transmute(self) } } - /// Return the memory representation of this integer as a byte array in - /// native byte order. - /// - /// [`to_ne_bytes`] should be preferred over this whenever possible. - /// - /// [`to_ne_bytes`]: Self::to_ne_bytes - /// - /// # Examples - /// - /// ``` - /// #![feature(num_as_ne_bytes)] - #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")] - /// let bytes = num.as_ne_bytes(); - /// assert_eq!( - /// bytes, - /// if cfg!(target_endian = "big") { - #[doc = concat!(" &", $be_bytes)] - /// } else { - #[doc = concat!(" &", $le_bytes)] - /// } - /// ); - /// ``` - #[unstable(feature = "num_as_ne_bytes", issue = "76976")] - #[inline] - pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] { - // SAFETY: integers are plain old datatypes so we can always transmute them to - // arrays of bytes - unsafe { &*(self as *const Self as *const _) } - } - /// Create an integer value from its representation as a byte array in /// big endian. /// diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index f9fd28b6a8c..e512d90ef37 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -417,8 +417,15 @@ macro_rules! uint_impl { } /// Unchecked integer addition. Computes `self + rhs`, assuming overflow - /// cannot occur. This results in undefined behavior when - #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`.")] + /// cannot occur. + /// + /// # Safety + /// + /// This results in undefined behavior when + #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")] + /// i.e. when [`checked_add`] would return `None`. + /// + #[doc = concat!("[`checked_add`]: ", stringify!($SelfT), "::checked_add")] #[unstable( feature = "unchecked_math", reason = "niche optimization path", @@ -456,8 +463,15 @@ macro_rules! uint_impl { } /// Unchecked integer subtraction. Computes `self - rhs`, assuming overflow - /// cannot occur. This results in undefined behavior when - #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`.")] + /// cannot occur. + /// + /// # Safety + /// + /// This results in undefined behavior when + #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")] + /// i.e. when [`checked_sub`] would return `None`. + /// + #[doc = concat!("[`checked_sub`]: ", stringify!($SelfT), "::checked_sub")] #[unstable( feature = "unchecked_math", reason = "niche optimization path", @@ -495,8 +509,15 @@ macro_rules! uint_impl { } /// Unchecked integer multiplication. Computes `self * rhs`, assuming overflow - /// cannot occur. This results in undefined behavior when - #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`.")] + /// cannot occur. + /// + /// # Safety + /// + /// This results in undefined behavior when + #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")] + /// i.e. when [`checked_mul`] would return `None`. + /// + #[doc = concat!("[`checked_mul`]: ", stringify!($SelfT), "::checked_mul")] #[unstable( feature = "unchecked_math", reason = "niche optimization path", @@ -655,6 +676,31 @@ macro_rules! uint_impl { if unlikely!(b) {None} else {Some(a)} } + /// Unchecked shift left. Computes `self << rhs`, assuming that + /// `rhs` is less than the number of bits in `self`. + /// + /// # Safety + /// + /// This results in undefined behavior if `rhs` is larger than + /// or equal to the number of bits in `self`, + /// i.e. when [`checked_shl`] would return `None`. + /// + #[doc = concat!("[`checked_shl`]: ", stringify!($SelfT), "::checked_shl")] + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "85122", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] + #[inline(always)] + pub const unsafe fn unchecked_shl(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_shl`. + unsafe { intrinsics::unchecked_shl(self, rhs) } + } + /// Checked shift right. Computes `self >> rhs`, returning `None` /// if `rhs` is larger than or equal to the number of bits in `self`. /// @@ -676,6 +722,31 @@ macro_rules! uint_impl { if unlikely!(b) {None} else {Some(a)} } + /// Unchecked shift right. Computes `self >> rhs`, assuming that + /// `rhs` is less than the number of bits in `self`. + /// + /// # Safety + /// + /// This results in undefined behavior if `rhs` is larger than + /// or equal to the number of bits in `self`, + /// i.e. when [`checked_shr`] would return `None`. + /// + #[doc = concat!("[`checked_shr`]: ", stringify!($SelfT), "::checked_shr")] + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "85122", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[rustc_const_unstable(feature = "const_inherent_unchecked_arith", issue = "85122")] + #[inline(always)] + pub const unsafe fn unchecked_shr(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_shr`. + unsafe { intrinsics::unchecked_shr(self, rhs) } + } + /// Checked exponentiation. Computes `self.pow(exp)`, returning `None` if /// overflow occurred. /// @@ -1672,36 +1743,6 @@ macro_rules! uint_impl { unsafe { mem::transmute(self) } } - /// Return the memory representation of this integer as a byte array in - /// native byte order. - /// - /// [`to_ne_bytes`] should be preferred over this whenever possible. - /// - /// [`to_ne_bytes`]: Self::to_ne_bytes - /// - /// # Examples - /// - /// ``` - /// #![feature(num_as_ne_bytes)] - #[doc = concat!("let num = ", $swap_op, stringify!($SelfT), ";")] - /// let bytes = num.as_ne_bytes(); - /// assert_eq!( - /// bytes, - /// if cfg!(target_endian = "big") { - #[doc = concat!(" &", $be_bytes)] - /// } else { - #[doc = concat!(" &", $le_bytes)] - /// } - /// ); - /// ``` - #[unstable(feature = "num_as_ne_bytes", issue = "76976")] - #[inline] - pub fn as_ne_bytes(&self) -> &[u8; mem::size_of::<Self>()] { - // SAFETY: integers are plain old datatypes so we can always transmute them to - // arrays of bytes - unsafe { &*(self as *const Self as *const _) } - } - /// Create a native endian integer value from its representation /// as a byte array in big endian. /// diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs index ecaff053bd5..9d9398fb56d 100644 --- a/library/core/src/ops/control_flow.rs +++ b/library/core/src/ops/control_flow.rs @@ -1,5 +1,4 @@ -use crate::convert; -use crate::ops::{self, Try}; +use crate::{convert, ops}; /// Used to tell an operation whether it should exit early or go on as usual. /// @@ -53,8 +52,10 @@ use crate::ops::{self, Try}; #[derive(Debug, Clone, Copy, PartialEq)] pub enum ControlFlow<B, C = ()> { /// Move on to the next phase of the operation as normal. + #[cfg_attr(not(bootstrap), lang = "Continue")] Continue(C), /// Exit the operation without running subsequent phases. + #[cfg_attr(not(bootstrap), lang = "Break")] Break(B), // Yes, the order of the variants doesn't match the type parameters. // They're in this order so that `ControlFlow<A, B>` <-> `Result<B, A>` @@ -62,11 +63,12 @@ pub enum ControlFlow<B, C = ()> { } #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] -impl<B, C> Try for ControlFlow<B, C> { - type Ok = C; +#[cfg(bootstrap)] +impl<B, C> ops::TryV1 for ControlFlow<B, C> { + type Output = C; type Error = B; #[inline] - fn into_result(self) -> Result<Self::Ok, Self::Error> { + fn into_result(self) -> Result<Self::Output, Self::Error> { match self { ControlFlow::Continue(y) => Ok(y), ControlFlow::Break(x) => Err(x), @@ -77,7 +79,7 @@ impl<B, C> Try for ControlFlow<B, C> { ControlFlow::Break(v) } #[inline] - fn from_ok(v: Self::Ok) -> Self { + fn from_ok(v: Self::Output) -> Self { ControlFlow::Continue(v) } } @@ -182,23 +184,46 @@ impl<B, C> ControlFlow<B, C> { } } -impl<R: Try> ControlFlow<R, R::Ok> { +#[cfg(bootstrap)] +impl<R: ops::TryV1> ControlFlow<R, R::Output> { /// Create a `ControlFlow` from any type implementing `Try`. - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] #[inline] - pub fn from_try(r: R) -> Self { - match Try::into_result(r) { + pub(crate) fn from_try(r: R) -> Self { + match R::into_result(r) { Ok(v) => ControlFlow::Continue(v), - Err(v) => ControlFlow::Break(Try::from_error(v)), + Err(v) => ControlFlow::Break(R::from_error(v)), + } + } + + /// Convert a `ControlFlow` into any type implementing `Try`; + #[inline] + pub(crate) fn into_try(self) -> R { + match self { + ControlFlow::Continue(v) => R::from_ok(v), + ControlFlow::Break(v) => v, + } + } +} + +/// These are used only as part of implementing the iterator adapters. +/// They have mediocre names and non-obvious semantics, so aren't +/// currently on a path to potential stabilization. +#[cfg(not(bootstrap))] +impl<R: ops::TryV2> ControlFlow<R, R::Output> { + /// Create a `ControlFlow` from any type implementing `Try`. + #[inline] + pub(crate) fn from_try(r: R) -> Self { + match R::branch(r) { + ControlFlow::Continue(v) => ControlFlow::Continue(v), + ControlFlow::Break(v) => ControlFlow::Break(R::from_residual(v)), } } /// Convert a `ControlFlow` into any type implementing `Try`; - #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] #[inline] - pub fn into_try(self) -> R { + pub(crate) fn into_try(self) -> R { match self { - ControlFlow::Continue(v) => Try::from_ok(v), + ControlFlow::Continue(v) => R::from_output(v), ControlFlow::Break(v) => v, } } diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 1b07936ccde..139a8c0eec9 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -147,6 +147,7 @@ mod function; mod generator; mod index; mod range; +#[cfg(bootstrap)] mod r#try; mod try_trait; mod unsize; @@ -183,13 +184,22 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; #[unstable(feature = "try_trait", issue = "42327")] +#[cfg(bootstrap)] pub use self::r#try::Try; +#[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")] +#[cfg(bootstrap)] +pub(crate) use self::r#try::Try as TryV1; + #[unstable(feature = "try_trait_v2", issue = "84277")] pub use self::try_trait::FromResidual; +#[unstable(feature = "try_trait_v2", issue = "84277")] +#[cfg(not(bootstrap))] +pub use self::try_trait::Try; + #[unstable(feature = "try_trait_transition", reason = "for bootstrap", issue = "none")] -pub use self::try_trait::Try as TryV2; +pub(crate) use self::try_trait::Try as TryV2; #[unstable(feature = "generator_trait", issue = "43122")] pub use self::generator::{Generator, GeneratorState}; diff --git a/library/core/src/ops/try.rs b/library/core/src/ops/try.rs index 3bede569978..9d659e78d3c 100644 --- a/library/core/src/ops/try.rs +++ b/library/core/src/ops/try.rs @@ -25,11 +25,11 @@ ) )] #[doc(alias = "?")] -#[lang = "try"] +#[cfg_attr(bootstrap, lang = "try")] pub trait Try { /// The type of this value when viewed as successful. #[unstable(feature = "try_trait", issue = "42327")] - type Ok; + type Output; // This no longer follows its RFC, but is only used in bootstrap. /// The type of this value when viewed as failed. #[unstable(feature = "try_trait", issue = "42327")] type Error; @@ -43,19 +43,19 @@ pub trait Try { /// in the return type of the enclosing scope (which must itself implement /// `Try`). Specifically, the value `X::from_error(From::from(e))` /// is returned, where `X` is the return type of the enclosing function. - #[lang = "into_result"] + #[cfg_attr(bootstrap, lang = "into_result")] #[unstable(feature = "try_trait", issue = "42327")] - fn into_result(self) -> Result<Self::Ok, Self::Error>; + fn into_result(self) -> Result<Self::Output, Self::Error>; /// Wrap an error value to construct the composite result. For example, /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. - #[lang = "from_error"] + #[cfg_attr(bootstrap, lang = "from_error")] #[unstable(feature = "try_trait", issue = "42327")] fn from_error(v: Self::Error) -> Self; /// Wrap an OK value to construct the composite result. For example, /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. - #[lang = "from_ok"] + #[cfg_attr(bootstrap, lang = "from_ok")] #[unstable(feature = "try_trait", issue = "42327")] - fn from_ok(v: Self::Ok) -> Self; + fn from_ok(v: Self::Output) -> Self; } diff --git a/library/core/src/ops/try_trait.rs b/library/core/src/ops/try_trait.rs index 0c819b000aa..1d9bc452618 100644 --- a/library/core/src/ops/try_trait.rs +++ b/library/core/src/ops/try_trait.rs @@ -41,8 +41,7 @@ use crate::ops::ControlFlow; /// output type that we want: /// ``` /// # #![feature(try_trait_v2)] -/// # #![feature(try_trait_transition)] -/// # use std::ops::TryV2 as Try; +/// # use std::ops::Try; /// fn simple_try_fold_1<A, T, R: Try<Output = A>>( /// iter: impl Iterator<Item = T>, /// mut accum: A, @@ -56,9 +55,8 @@ use crate::ops::ControlFlow; /// into the return type using [`Try::from_output`]: /// ``` /// # #![feature(try_trait_v2)] -/// # #![feature(try_trait_transition)] /// # #![feature(control_flow_enum)] -/// # use std::ops::{ControlFlow, TryV2 as Try}; +/// # use std::ops::{ControlFlow, Try}; /// fn simple_try_fold_2<A, T, R: Try<Output = A>>( /// iter: impl Iterator<Item = T>, /// mut accum: A, @@ -81,9 +79,8 @@ use crate::ops::ControlFlow; /// recreated from their corresponding residual, so we'll just call it: /// ``` /// # #![feature(try_trait_v2)] -/// # #![feature(try_trait_transition)] /// # #![feature(control_flow_enum)] -/// # use std::ops::{ControlFlow, TryV2 as Try}; +/// # use std::ops::{ControlFlow, Try}; /// pub fn simple_try_fold_3<A, T, R: Try<Output = A>>( /// iter: impl Iterator<Item = T>, /// mut accum: A, @@ -103,10 +100,9 @@ use crate::ops::ControlFlow; /// But this "call `branch`, then `match` on it, and `return` if it was a /// `Break`" is exactly what happens inside the `?` operator. So rather than /// do all this manually, we can just use `?` instead: -/// ```compile_fail (enable again once ? converts to the new trait) +/// ``` /// # #![feature(try_trait_v2)] -/// # #![feature(try_trait_transition)] -/// # use std::ops::TryV2 as Try; +/// # use std::ops::Try; /// fn simple_try_fold<A, T, R: Try<Output = A>>( /// iter: impl Iterator<Item = T>, /// mut accum: A, @@ -119,6 +115,22 @@ use crate::ops::ControlFlow; /// } /// ``` #[unstable(feature = "try_trait_v2", issue = "84277")] +#[rustc_on_unimplemented( + on( + all(from_method = "from_output", from_desugaring = "TryBlock"), + message = "a `try` block must return `Result` or `Option` \ + (or another type that implements `{Try}`)", + label = "could not wrap the final value of the block as `{Self}` doesn't implement `Try`", + ), + on( + all(from_method = "branch", from_desugaring = "QuestionMark"), + message = "the `?` operator can only be applied to values \ + that implement `{Try}`", + label = "the `?` operator cannot be applied to type `{Self}`" + ) +)] +#[doc(alias = "?")] +#[cfg_attr(not(bootstrap), lang = "Try")] pub trait Try: FromResidual { /// The type of the value produced by `?` when *not* short-circuiting. #[unstable(feature = "try_trait_v2", issue = "84277")] @@ -159,8 +171,7 @@ pub trait Try: FromResidual { /// ``` /// #![feature(try_trait_v2)] /// #![feature(control_flow_enum)] - /// #![feature(try_trait_transition)] - /// use std::ops::TryV2 as Try; + /// use std::ops::Try; /// /// assert_eq!(<Result<_, String> as Try>::from_output(3), Ok(3)); /// assert_eq!(<Option<_> as Try>::from_output(4), Some(4)); @@ -178,6 +189,7 @@ pub trait Try: FromResidual { /// let r = std::iter::empty().try_fold(4, |_, ()| -> Option<_> { unreachable!() }); /// assert_eq!(r, Some(4)); /// ``` + #[cfg_attr(not(bootstrap), lang = "from_output")] #[unstable(feature = "try_trait_v2", issue = "84277")] fn from_output(output: Self::Output) -> Self; @@ -191,8 +203,7 @@ pub trait Try: FromResidual { /// ``` /// #![feature(try_trait_v2)] /// #![feature(control_flow_enum)] - /// #![feature(try_trait_transition)] - /// use std::ops::{ControlFlow, TryV2 as Try}; + /// use std::ops::{ControlFlow, Try}; /// /// assert_eq!(Ok::<_, String>(3).branch(), ControlFlow::Continue(3)); /// assert_eq!(Err::<String, _>(3).branch(), ControlFlow::Break(Err(3))); @@ -206,15 +217,105 @@ pub trait Try: FromResidual { /// ControlFlow::Break(ControlFlow::Break(3)), /// ); /// ``` + #[cfg_attr(not(bootstrap), lang = "branch")] #[unstable(feature = "try_trait_v2", issue = "84277")] fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; } -/// Used to specify which residuals can be converted into which [`Try`] types. +/// Used to specify which residuals can be converted into which [`crate::ops::Try`] types. /// /// Every `Try` type needs to be recreatable from its own associated /// `Residual` type, but can also have additional `FromResidual` implementations /// to support interconversion with other `Try` types. +#[rustc_on_unimplemented( + on( + all( + from_method = "from_residual", + from_desugaring = "QuestionMark", + _Self = "std::result::Result<T, E>", + R = "std::option::Option<std::convert::Infallible>" + ), + message = "the `?` operator can only be used on `Result`s, not `Option`s, \ + in {ItemContext} that returns `Result`", + label = "use `.ok_or(...)?` to provide an error compatible with `{Self}`", + enclosing_scope = "this function returns a `Result`" + ), + on( + all( + from_method = "from_residual", + from_desugaring = "QuestionMark", + _Self = "std::result::Result<T, E>", + ), + // There's a special error message in the trait selection code for + // `From` in `?`, so this is not shown for result-in-result errors, + // and thus it can be phrased more strongly than `ControlFlow`'s. + message = "the `?` operator can only be used on `Result`s \ + in {ItemContext} that returns `Result`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + enclosing_scope = "this function returns a `Result`" + ), + on( + all( + from_method = "from_residual", + from_desugaring = "QuestionMark", + _Self = "std::option::Option<T>", + R = "std::result::Result<T, E>", + ), + message = "the `?` operator can only be used on `Option`s, not `Result`s, \ + in {ItemContext} that returns `Option`", + label = "use `.ok()?` if you want to discard the `{R}` error information", + enclosing_scope = "this function returns an `Option`" + ), + on( + all( + from_method = "from_residual", + from_desugaring = "QuestionMark", + _Self = "std::option::Option<T>", + ), + // `Option`-in-`Option` always works, as there's only one possible + // residual, so this can also be phrased strongly. + message = "the `?` operator can only be used on `Option`s \ + in {ItemContext} that returns `Option`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + enclosing_scope = "this function returns an `Option`" + ), + on( + all( + from_method = "from_residual", + from_desugaring = "QuestionMark", + _Self = "std::ops::ControlFlow<B, C>", + R = "std::ops::ControlFlow<B, C>", + ), + message = "the `?` operator in {ItemContext} that returns `ControlFlow<B, _>` \ + can only be used on other `ControlFlow<B, _>`s (with the same Break type)", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + enclosing_scope = "this function returns a `ControlFlow`", + note = "unlike `Result`, there's no `From`-conversion performed for `ControlFlow`" + ), + on( + all( + from_method = "from_residual", + from_desugaring = "QuestionMark", + _Self = "std::ops::ControlFlow<B, C>", + // `R` is not a `ControlFlow`, as that case was matched previously + ), + message = "the `?` operator can only be used on `ControlFlow`s \ + in {ItemContext} that returns `ControlFlow`", + label = "this `?` produces `{R}`, which is incompatible with `{Self}`", + enclosing_scope = "this function returns a `ControlFlow`", + ), + on( + all( + from_method = "from_residual", + from_desugaring = "QuestionMark" + ), + message = "the `?` operator can only be used in {ItemContext} \ + that returns `Result` or `Option` \ + (or another type that implements `{FromResidual}`)", + label = "cannot use the `?` operator in {ItemContext} that returns `{Self}`", + enclosing_scope = "this function should return `Result` or `Option` to accept `?`" + ), +)] #[unstable(feature = "try_trait_v2", issue = "84277")] pub trait FromResidual<R = <Self as Try>::Residual> { /// Constructs the type from a compatible `Residual` type. @@ -238,6 +339,7 @@ pub trait FromResidual<R = <Self as Try>::Residual> { /// ControlFlow::Break(5), /// ); /// ``` + #[cfg_attr(not(bootstrap), lang = "from_residual")] #[unstable(feature = "try_trait_v2", issue = "84277")] fn from_residual(residual: R) -> Self; } diff --git a/library/core/src/option.rs b/library/core/src/option.rs index 04551dded8c..4e7afca6a49 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -83,6 +83,8 @@ //! * [`ptr::NonNull<U>`] //! * `#[repr(transparent)]` struct around one of the types in this list. //! +//! This is called the "null pointer optimization" or NPO. +//! //! It is further guaranteed that, for the cases above, one can //! [`mem::transmute`] from all valid values of `T` to `Option<T>` and //! from `Some::<T>(_)` to `T` (but transmuting `None::<T>` to `T` @@ -209,7 +211,7 @@ impl<T> Option<T> { /// assert_eq!(x.is_none(), true); /// ``` #[must_use = "if you intended to assert that this doesn't have a value, consider \ - `.and_then(|| panic!(\"`Option` had a value when expected `None`\"))` instead"] + `.and_then(|_| panic!(\"`Option` had a value when expected `None`\"))` instead"] #[inline] #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] @@ -1641,11 +1643,13 @@ impl<A, V: FromIterator<A>> FromIterator<Option<A>> for Option<V> { #[rustc_diagnostic_item = "none_error"] #[unstable(feature = "try_trait", issue = "42327")] #[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Debug, Hash)] +#[cfg(bootstrap)] pub struct NoneError; #[unstable(feature = "try_trait", issue = "42327")] -impl<T> ops::Try for Option<T> { - type Ok = T; +#[cfg(bootstrap)] +impl<T> ops::TryV1 for Option<T> { + type Output = T; type Error = NoneError; #[inline] diff --git a/library/core/src/prelude/mod.rs b/library/core/src/prelude/mod.rs index 8f57db49496..79753c1fb66 100644 --- a/library/core/src/prelude/mod.rs +++ b/library/core/src/prelude/mod.rs @@ -11,9 +11,9 @@ pub mod v1; /// The 2015 version of the core prelude. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2015", issue = "none")] +#[unstable(feature = "prelude_2015", issue = "85684")] pub mod rust_2015 { - #[unstable(feature = "prelude_2015", issue = "none")] + #[unstable(feature = "prelude_2015", issue = "85684")] #[doc(no_inline)] pub use super::v1::*; } @@ -21,9 +21,9 @@ pub mod rust_2015 { /// The 2018 version of the core prelude. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2018", issue = "none")] +#[unstable(feature = "prelude_2018", issue = "85684")] pub mod rust_2018 { - #[unstable(feature = "prelude_2018", issue = "none")] + #[unstable(feature = "prelude_2018", issue = "85684")] #[doc(no_inline)] pub use super::v1::*; } @@ -31,11 +31,17 @@ pub mod rust_2018 { /// The 2021 version of the core prelude. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2021", issue = "none")] +#[unstable(feature = "prelude_2021", issue = "85684")] pub mod rust_2021 { - #[unstable(feature = "prelude_2021", issue = "none")] + #[unstable(feature = "prelude_2021", issue = "85684")] #[doc(no_inline)] pub use super::v1::*; - // FIXME: Add more things. + #[unstable(feature = "prelude_2021", issue = "85684")] + #[doc(no_inline)] + pub use crate::iter::FromIterator; + + #[unstable(feature = "prelude_2021", issue = "85684")] + #[doc(no_inline)] + pub use crate::convert::{TryFrom, TryInto}; } diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 2c324b15a1a..214d7c8bc15 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -342,10 +342,12 @@ pub const fn slice_from_raw_parts_mut<T>(data: *mut T, len: usize) -> *mut [T] { /// ``` /// use std::ptr; /// -/// let mut array = [0, 1, 2, 3]; +/// let mut array: [i32; 4] = [0, 1, 2, 3]; +/// +/// let array_ptr: *mut i32 = array.as_mut_ptr(); /// -/// let x = array[0..].as_mut_ptr() as *mut [u32; 3]; // this is `array[0..3]` -/// let y = array[1..].as_mut_ptr() as *mut [u32; 3]; // this is `array[1..4]` +/// let x = array_ptr as *mut [i32; 3]; // this is `array[0..3]` +/// let y = unsafe { array_ptr.add(1) } as *mut [i32; 3]; // this is `array[1..4]` /// /// unsafe { /// ptr::swap(x, y); diff --git a/library/core/src/result.rs b/library/core/src/result.rs index e0071f806aa..babd0a0b552 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -1627,8 +1627,9 @@ impl<A, E, V: FromIterator<A>> FromIterator<Result<A, E>> for Result<V, E> { } #[unstable(feature = "try_trait", issue = "42327")] -impl<T, E> ops::Try for Result<T, E> { - type Ok = T; +#[cfg(bootstrap)] +impl<T, E> ops::TryV1 for Result<T, E> { + type Output = T; type Error = E; #[inline] diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 906dcb1e8bc..b92ab7e3475 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -110,7 +110,7 @@ impl<'a> iter::Iterator for EscapeAscii<'a> { fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where Fold: FnMut(Acc, Self::Item) -> R, - R: ops::Try<Ok = Acc>, + R: ops::Try<Output = Acc>, { self.inner.try_fold(init, fold) } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 0923175414e..3bcea4e6d25 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -3096,7 +3096,11 @@ impl<T> [T] { // SAFETY: the conditions for `ptr::copy` have all been checked above, // as have those for `ptr::add`. unsafe { - ptr::copy(self.as_ptr().add(src_start), self.as_mut_ptr().add(dest), count); + // Derive both `src_ptr` and `dest_ptr` from the same loan + let ptr = self.as_mut_ptr(); + let src_ptr = ptr.add(src_start); + let dest_ptr = ptr.add(dest); + ptr::copy(src_ptr, dest_ptr, count); } } diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs index 724137aba9f..6ec6b70b571 100644 --- a/library/core/src/str/iter.rs +++ b/library/core/src/str/iter.rs @@ -1467,7 +1467,7 @@ macro_rules! escape_types_impls { #[inline] fn try_fold<Acc, Fold, R>(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Ok=Acc> + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try<Output = Acc> { self.inner.try_fold(init, fold) } diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 2765c21a46d..9cf89623d88 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -1,7 +1,7 @@ #![stable(feature = "futures_api", since = "1.36.0")] use crate::convert; -use crate::ops::{self, ControlFlow, Try}; +use crate::ops::{self, ControlFlow}; use crate::result::Result; /// Indicates whether a value is available or if the current task has been @@ -129,12 +129,13 @@ impl<T> From<T> for Poll<T> { } #[stable(feature = "futures_api", since = "1.36.0")] -impl<T, E> Try for Poll<Result<T, E>> { - type Ok = Poll<T>; +#[cfg(bootstrap)] +impl<T, E> ops::TryV1 for Poll<Result<T, E>> { + type Output = Poll<T>; type Error = E; #[inline] - fn into_result(self) -> Result<Self::Ok, Self::Error> { + fn into_result(self) -> Result<Self::Output, Self::Error> { match self { Poll::Ready(Ok(x)) => Ok(Poll::Ready(x)), Poll::Ready(Err(e)) => Err(e), @@ -148,7 +149,7 @@ impl<T, E> Try for Poll<Result<T, E>> { } #[inline] - fn from_ok(x: Self::Ok) -> Self { + fn from_ok(x: Self::Output) -> Self { x.map(Ok) } } @@ -184,12 +185,13 @@ impl<T, E, F: From<E>> ops::FromResidual<Result<convert::Infallible, E>> for Pol } #[stable(feature = "futures_api", since = "1.36.0")] -impl<T, E> Try for Poll<Option<Result<T, E>>> { - type Ok = Poll<Option<T>>; +#[cfg(bootstrap)] +impl<T, E> ops::TryV1 for Poll<Option<Result<T, E>>> { + type Output = Poll<Option<T>>; type Error = E; #[inline] - fn into_result(self) -> Result<Self::Ok, Self::Error> { + fn into_result(self) -> Result<Self::Output, Self::Error> { match self { Poll::Ready(Some(Ok(x))) => Ok(Poll::Ready(Some(x))), Poll::Ready(Some(Err(e))) => Err(e), @@ -204,7 +206,7 @@ impl<T, E> Try for Poll<Option<Result<T, E>>> { } #[inline] - fn from_ok(x: Self::Ok) -> Self { + fn from_ok(x: Self::Output) -> Self { x.map(|x| x.map(Ok)) } } diff --git a/library/core/tests/any.rs b/library/core/tests/any.rs index b0dc9903464..b36d6f0d404 100644 --- a/library/core/tests/any.rs +++ b/library/core/tests/any.rs @@ -114,3 +114,16 @@ fn any_unsized() { fn is_any<T: Any + ?Sized>() {} is_any::<[i32]>(); } + +#[test] +fn distinct_type_names() { + // https://github.com/rust-lang/rust/issues/84666 + + struct Velocity(f32, f32); + + fn type_name_of_val<T>(_: T) -> &'static str { + type_name::<T>() + } + + assert_ne!(type_name_of_val(Velocity), type_name_of_val(Velocity(0.0, -9.8)),); +} diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 35e4d213dde..16051b3bc36 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -40,11 +40,10 @@ #![feature(maybe_uninit_write_slice)] #![feature(min_specialization)] #![feature(step_trait)] -#![feature(step_trait_ext)] #![feature(str_internals)] #![feature(test)] #![feature(trusted_len)] -#![feature(try_trait)] +#![feature(try_trait_v2)] #![feature(slice_internals)] #![feature(slice_partition_dedup)] #![feature(int_error_matching)] diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index 9470451278c..88ea15a3b33 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -301,18 +301,6 @@ fn test_try() { Some(val) } assert_eq!(try_option_none(), None); - - fn try_option_ok() -> Result<u8, NoneError> { - let val = Some(1)?; - Ok(val) - } - assert_eq!(try_option_ok(), Ok(1)); - - fn try_option_err() -> Result<u8, NoneError> { - let val = None?; - Ok(val) - } - assert_eq!(try_option_err(), Err(NoneError)); } #[test] diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index c461ab380ad..f4e5e7751b8 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -249,26 +249,14 @@ pub fn test_into_err() { #[test] fn test_try() { - fn try_result_some() -> Option<u8> { - let val = Ok(1)?; - Some(val) - } - assert_eq!(try_result_some(), Some(1)); - - fn try_result_none() -> Option<u8> { - let val = Err(NoneError)?; - Some(val) - } - assert_eq!(try_result_none(), None); - - fn try_result_ok() -> Result<u8, u8> { + fn try_result_ok() -> Result<u8, u32> { let result: Result<u8, u8> = Ok(1); let val = result?; Ok(val) } assert_eq!(try_result_ok(), Ok(1)); - fn try_result_err() -> Result<u8, u8> { + fn try_result_err() -> Result<u8, u32> { let result: Result<u8, u8> = Err(1); let val = result?; Ok(val) @@ -401,3 +389,17 @@ fn result_opt_conversions() { assert_eq!(res, Err(BadNumErr)) } + +#[test] +#[cfg(not(bootstrap))] // Needs the V2 trait +fn result_try_trait_v2_branch() { + use core::num::NonZeroU32; + use core::ops::{ControlFlow::*, Try}; + assert_eq!(Ok::<i32, i32>(4).branch(), Continue(4)); + assert_eq!(Err::<i32, i32>(4).branch(), Break(Err(4))); + let one = NonZeroU32::new(1).unwrap(); + assert_eq!(Ok::<(), NonZeroU32>(()).branch(), Continue(())); + assert_eq!(Err::<(), NonZeroU32>(one).branch(), Break(Err(one))); + assert_eq!(Ok::<NonZeroU32, ()>(one).branch(), Continue(one)); + assert_eq!(Err::<NonZeroU32, ()>(()).branch(), Break(Err(()))); +} diff --git a/library/proc_macro/src/bridge/buffer.rs b/library/proc_macro/src/bridge/buffer.rs index aeecbd49662..717201aef10 100644 --- a/library/proc_macro/src/bridge/buffer.rs +++ b/library/proc_macro/src/bridge/buffer.rs @@ -39,7 +39,7 @@ pub struct Buffer<T: Copy> { data: *mut T, len: usize, capacity: usize, - extend_from_slice: extern "C" fn(Buffer<T>, Slice<'_, T>) -> Buffer<T>, + reserve: extern "C" fn(Buffer<T>, usize) -> Buffer<T>, drop: extern "C" fn(Buffer<T>), } @@ -78,18 +78,44 @@ impl<T: Copy> Buffer<T> { mem::take(self) } + // We have the array method separate from extending from a slice. This is + // because in the case of small arrays, codegen can be more efficient + // (avoiding a memmove call). With extend_from_slice, LLVM at least + // currently is not able to make that optimization. + pub(super) fn extend_from_array<const N: usize>(&mut self, xs: &[T; N]) { + if xs.len() > (self.capacity - self.len) { + let b = self.take(); + *self = (b.reserve)(b, xs.len()); + } + unsafe { + xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); + self.len += xs.len(); + } + } + pub(super) fn extend_from_slice(&mut self, xs: &[T]) { - // Fast path to avoid going through an FFI call. - if let Some(final_len) = self.len.checked_add(xs.len()) { - if final_len <= self.capacity { - let dst = unsafe { slice::from_raw_parts_mut(self.data, self.capacity) }; - dst[self.len..][..xs.len()].copy_from_slice(xs); - self.len = final_len; - return; - } + if xs.len() > (self.capacity - self.len) { + let b = self.take(); + *self = (b.reserve)(b, xs.len()); + } + unsafe { + xs.as_ptr().copy_to_nonoverlapping(self.data.add(self.len), xs.len()); + self.len += xs.len(); + } + } + + pub(super) fn push(&mut self, v: T) { + // The code here is taken from Vec::push, and we know that reserve() + // will panic if we're exceeding isize::MAX bytes and so there's no need + // to check for overflow. + if self.len == self.capacity { + let b = self.take(); + *self = (b.reserve)(b, 1); + } + unsafe { + *self.data.add(self.len) = v; + self.len += 1; } - let b = self.take(); - *self = (b.extend_from_slice)(b, Slice::from(xs)); } } @@ -131,9 +157,9 @@ impl<T: Copy> From<Vec<T>> for Buffer<T> { } } - extern "C" fn extend_from_slice<T: Copy>(b: Buffer<T>, xs: Slice<'_, T>) -> Buffer<T> { + extern "C" fn reserve<T: Copy>(b: Buffer<T>, additional: usize) -> Buffer<T> { let mut v = to_vec(b); - v.extend_from_slice(&xs); + v.reserve(additional); Buffer::from(v) } @@ -141,6 +167,6 @@ impl<T: Copy> From<Vec<T>> for Buffer<T> { mem::drop(to_vec(b)); } - Buffer { data, len, capacity, extend_from_slice, drop } + Buffer { data, len, capacity, reserve, drop } } } diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 355ad1f9f88..a2953b68564 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -107,6 +107,7 @@ macro_rules! with_api { Literal { fn drop($self: $S::Literal); fn clone($self: &$S::Literal) -> $S::Literal; + fn from_str(s: &str) -> Result<$S::Literal, ()>; fn debug_kind($self: &$S::Literal) -> String; fn symbol($self: &$S::Literal) -> String; fn suffix($self: &$S::Literal) -> Option<String>; @@ -315,6 +316,19 @@ impl<T: Unmark> Unmark for Option<T> { } } +impl<T: Mark, E: Mark> Mark for Result<T, E> { + type Unmarked = Result<T::Unmarked, E::Unmarked>; + fn mark(unmarked: Self::Unmarked) -> Self { + unmarked.map(T::mark).map_err(E::mark) + } +} +impl<T: Unmark, E: Unmark> Unmark for Result<T, E> { + type Unmarked = Result<T::Unmarked, E::Unmarked>; + fn unmark(self) -> Self::Unmarked { + self.map(T::unmark).map_err(E::unmark) + } +} + macro_rules! mark_noop { ($($ty:ty),* $(,)?) => { $( diff --git a/library/proc_macro/src/bridge/rpc.rs b/library/proc_macro/src/bridge/rpc.rs index 5c2f9ec9848..588e6ded0f4 100644 --- a/library/proc_macro/src/bridge/rpc.rs +++ b/library/proc_macro/src/bridge/rpc.rs @@ -27,7 +27,7 @@ macro_rules! rpc_encode_decode { (le $ty:ty) => { impl<S> Encode<S> for $ty { fn encode(self, w: &mut Writer, _: &mut S) { - w.write_all(&self.to_le_bytes()).unwrap(); + w.extend_from_array(&self.to_le_bytes()); } } @@ -114,7 +114,7 @@ impl<S> DecodeMut<'_, '_, S> for () { impl<S> Encode<S> for u8 { fn encode(self, w: &mut Writer, _: &mut S) { - w.write_all(&[self]).unwrap(); + w.push(self); } } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index 525fd0fbe34..04a165e09f1 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -21,8 +21,7 @@ #![feature(rustc_allow_const_fn_unstable)] #![feature(nll)] #![feature(staged_api)] -#![cfg_attr(bootstrap, feature(const_fn))] -#![cfg_attr(not(bootstrap), feature(const_fn_trait_bound))] +#![feature(const_fn_trait_bound)] #![feature(const_fn_fn_ptr_basics)] #![feature(allow_internal_unstable)] #![feature(decl_macro)] @@ -91,6 +90,12 @@ pub struct LexError { _inner: (), } +impl LexError { + fn new() -> Self { + LexError { _inner: () } + } +} + #[stable(feature = "proc_macro_lexerror_impls", since = "1.44.0")] impl fmt::Display for LexError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -1171,6 +1176,28 @@ impl Literal { } } +/// Parse a single literal from its stringified representation. +/// +/// In order to parse successfully, the input string must not contain anything +/// but the literal token. Specifically, it must not contain whitespace or +/// comments in addition to the literal. +/// +/// The resulting literal token will have a `Span::call_site()` span. +/// +/// NOTE: some errors may cause panics instead of returning `LexError`. We +/// reserve the right to change these errors into `LexError`s later. +#[stable(feature = "proc_macro_literal_parse", since = "1.54.0")] +impl FromStr for Literal { + type Err = LexError; + + fn from_str(src: &str) -> Result<Self, LexError> { + match bridge::client::Literal::from_str(src) { + Ok(literal) => Ok(Literal(literal)), + Err(()) => Err(LexError::new()), + } + } +} + // N.B., the bridge only provides `to_string`, implement `fmt::Display` // based on it (the reverse of the usual relationship between the two). #[stable(feature = "proc_macro_lib", since = "1.15.0")] diff --git a/library/profiler_builtins/Cargo.toml b/library/profiler_builtins/Cargo.toml index 474058a547f..7b7ca8029b4 100644 --- a/library/profiler_builtins/Cargo.toml +++ b/library/profiler_builtins/Cargo.toml @@ -14,4 +14,4 @@ core = { path = "../core" } compiler_builtins = { version = "0.1.0", features = ['rustc-dep-of-std'] } [build-dependencies] -cc = "1.0.67" +cc = "1.0.68" diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 922c2c2bb8c..415d874c7fa 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -17,7 +17,7 @@ panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } libc = { version = "0.2.93", default-features = false, features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.43" } +compiler_builtins = { version = "0.1.44" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } hashbrown = { version = "0.11", default-features = false, features = ['rustc-dep-of-std'] } diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index 843ef09a584..8ee55234cea 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -63,8 +63,6 @@ use core::ptr::NonNull; use core::sync::atomic::{AtomicPtr, Ordering}; use core::{mem, ptr}; -use crate::sys_common::util::dumb_print; - #[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] pub use alloc_crate::alloc::*; @@ -317,7 +315,7 @@ pub fn take_alloc_error_hook() -> fn(Layout) { } fn default_alloc_error_hook(layout: Layout) { - dumb_print(format_args!("memory allocation of {} bytes failed\n", layout.size())); + rtprintpanic!("memory allocation of {} bytes failed\n", layout.size()); } #[cfg(not(test))] diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 2f9845d7536..be7e099b73a 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -10,7 +10,6 @@ use crate::error::Error; use crate::fmt::{self, Write}; use crate::io; use crate::mem; -use crate::memchr; use crate::num::NonZeroU8; use crate::ops; use crate::os::raw::c_char; @@ -20,6 +19,7 @@ use crate::slice; use crate::str::{self, Utf8Error}; use crate::sync::Arc; use crate::sys; +use crate::sys_common::memchr; /// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the /// middle. @@ -185,6 +185,7 @@ pub struct CString { /// /// [`&str`]: prim@str #[derive(Hash)] +#[cfg_attr(not(test), rustc_diagnostic_item = "CStr")] #[stable(feature = "rust1", since = "1.0.0")] // FIXME: // `fn from` in `impl From<&CStr> for Box<CStr>` current implementation relies @@ -671,6 +672,7 @@ impl CString { } /// Bypass "move out of struct which implements [`Drop`] trait" restriction. + #[inline] fn into_inner(self) -> Box<[u8]> { // Rationale: `mem::forget(self)` invalidates the previous call to `ptr::read(&self.inner)` // so we use `ManuallyDrop` to ensure `self` is not dropped. diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index e6120b8ee31..a1636e2f604 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -2208,3 +2208,29 @@ impl AsInnerMut<fs_imp::DirBuilder> for DirBuilder { &mut self.inner } } + +/// Returns `Ok(true)` if the path points at an existing entity. +/// +/// This function will traverse symbolic links to query information about the +/// destination file. In case of broken symbolic links this will return `Ok(false)`. +/// +/// As opposed to the `exists()` method, this one doesn't silently ignore errors +/// unrelated to the path not existing. (E.g. it will return `Err(_)` in case of permission +/// denied on some of the parent directories.) +/// +/// # Examples +/// +/// ```no_run +/// #![feature(path_try_exists)] +/// use std::fs; +/// +/// assert!(!fs::try_exists("does_not_exist.txt").expect("Can't check existence of file does_not_exist.txt")); +/// assert!(fs::try_exists("/root/secret_file.txt").is_err()); +/// ``` +// FIXME: stabilization should modify documentation of `exists()` to recommend this method +// instead. +#[unstable(feature = "path_try_exists", issue = "83186")] +#[inline] +pub fn try_exists<P: AsRef<Path>>(path: P) -> io::Result<bool> { + fs_imp::try_exists(path.as_ref()) +} diff --git a/library/std/src/io/buffered/linewritershim.rs b/library/std/src/io/buffered/linewritershim.rs index d0c859d2e0c..0175d2693e8 100644 --- a/library/std/src/io/buffered/linewritershim.rs +++ b/library/std/src/io/buffered/linewritershim.rs @@ -1,5 +1,5 @@ use crate::io::{self, BufWriter, IoSlice, Write}; -use crate::memchr; +use crate::sys_common::memchr; /// Private helper struct for implementing the line-buffered writing logic. /// This shim temporarily wraps a BufWriter, and uses its internals to diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 9021b470065..9527254c947 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -71,7 +71,7 @@ use core::convert::TryInto; /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone, Debug, Default, Eq, PartialEq)] +#[derive(Debug, Default, Eq, PartialEq)] pub struct Cursor<T> { inner: T, pos: u64, @@ -206,6 +206,23 @@ impl<T> Cursor<T> { } #[stable(feature = "rust1", since = "1.0.0")] +impl<T> Clone for Cursor<T> +where + T: Clone, +{ + #[inline] + fn clone(&self) -> Self { + Cursor { inner: self.inner.clone(), pos: self.pos } + } + + #[inline] + fn clone_from(&mut self, other: &Self) { + self.inner.clone_from(&other.inner); + self.pos = other.pos; + } +} + +#[stable(feature = "rust1", since = "1.0.0")] impl<T> io::Seek for Cursor<T> where T: AsRef<[u8]>, diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 9f43379aff7..4c154dbe01a 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -253,12 +253,12 @@ mod tests; use crate::cmp; use crate::fmt; -use crate::memchr; use crate::ops::{Deref, DerefMut}; use crate::ptr; use crate::slice; use crate::str; use crate::sys; +use crate::sys_common::memchr; #[stable(feature = "rust1", since = "1.0.0")] pub use self::buffered::IntoInnerError; @@ -509,8 +509,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [ /// [`std::io`]: self /// [`File`]: crate::fs::File #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(bootstrap, doc(spotlight))] -#[cfg_attr(not(bootstrap), doc(notable_trait))] +#[doc(notable_trait)] pub trait Read { /// Pull some bytes from this source into the specified buffer, returning /// how many bytes were read. @@ -526,7 +525,12 @@ pub trait Read { /// /// 1. This reader has reached its "end of file" and will likely no longer /// be able to produce bytes. Note that this does not mean that the - /// reader will *always* no longer be able to produce bytes. + /// reader will *always* no longer be able to produce bytes. As an example, + /// on Linux, this method will call the `recv` syscall for a [`TcpStream`], + /// where returning zero indicates the connection was shut down correctly. While + /// for [`File`], it is possible to reach the end of file and get zero as result, + /// but if more data is appended to the file, future calls to `read` will return + /// more data. /// 2. The buffer specified was 0 bytes in length. /// /// It is not an error if the returned value `n` is smaller than the buffer size, @@ -568,6 +572,7 @@ pub trait Read { /// /// [`Ok(n)`]: Ok /// [`File`]: crate::fs::File + /// [`TcpStream`]: crate::net::TcpStream /// /// ```no_run /// use std::io; @@ -1301,8 +1306,7 @@ impl Initializer { /// /// [`write_all`]: Write::write_all #[stable(feature = "rust1", since = "1.0.0")] -#[cfg_attr(bootstrap, doc(spotlight))] -#[cfg_attr(not(bootstrap), doc(notable_trait))] +#[doc(notable_trait)] pub trait Write { /// Write a buffer into this writer, returning how many bytes were written. /// @@ -1663,7 +1667,7 @@ pub trait Seek { /// /// # Errors /// - /// Seeking can fail, for example becaue it might involve flushing a buffer. + /// Seeking can fail, for example because it might involve flushing a buffer. /// /// Seeking to a negative offset is considered an error. #[stable(feature = "rust1", since = "1.0.0")] @@ -1675,7 +1679,7 @@ pub trait Seek { /// /// # Errors /// - /// Rewinding can fail, for example becaue it might involve flushing a buffer. + /// Rewinding can fail, for example because it might involve flushing a buffer. /// /// # Example /// diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index 39ed62425ce..ba2b8b6955d 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -1008,9 +1008,9 @@ mod mod_keyword {} /// move || println!("This is a: {}", text) /// } /// -/// let fn_plain = create_fn(); +/// let fn_plain = create_fn(); /// -/// fn_plain(); +/// fn_plain(); /// ``` /// /// `move` is often used when [threads] are involved. diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5f89ac059fd..8e4c63762fd 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -260,15 +260,14 @@ #![feature(doc_cfg)] #![feature(doc_keyword)] #![feature(doc_masked)] -#![cfg_attr(bootstrap, feature(doc_spotlight))] -#![cfg_attr(not(bootstrap), feature(doc_notable_trait))] +#![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] #![feature(duration_constants)] #![feature(edition_panic)] #![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] #![feature(extend_one)] -#![feature(extended_key_value_attributes)] +#![cfg_attr(bootstrap, feature(extended_key_value_attributes))] #![feature(fn_traits)] #![feature(format_args_nl)] #![feature(gen_future)] @@ -300,7 +299,6 @@ #![feature(nonnull_slice_from_raw_parts)] #![feature(once_cell)] #![feature(auto_traits)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(panic_info_message)] #![feature(panic_internals)] #![feature(panic_unwind)] @@ -530,7 +528,6 @@ mod sys; pub mod alloc; // Private support modules -mod memchr; mod panicking; // The runtime entry point and a few unstable public functions used by the diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 9b629e19be5..6c2f2eeabd6 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -1,11 +1,3 @@ -#![unstable( - feature = "ip", - reason = "extra functionality has not been \ - scrutinized to the level that it should \ - be to be stable", - issue = "27709" -)] - // Tests for this module #[cfg(all(test, not(target_os = "emscripten")))] mod tests; @@ -126,6 +118,7 @@ pub struct Ipv6Addr { #[allow(missing_docs)] #[derive(Copy, PartialEq, Eq, Clone, Hash, Debug)] +#[unstable(feature = "ip", issue = "27709")] pub enum Ipv6MulticastScope { InterfaceLocal, LinkLocal, @@ -199,6 +192,7 @@ impl IpAddr { /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); /// ``` #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_global(&self) -> bool { match self { @@ -249,6 +243,7 @@ impl IpAddr { /// ); /// ``` #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_documentation(&self) -> bool { match self { @@ -549,6 +544,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); /// ``` #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_global(&self) -> bool { // check if this address is 192.0.0.9 or 192.0.0.10. These addresses are the only two @@ -587,6 +583,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); /// ``` #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_shared(&self) -> bool { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) @@ -620,6 +617,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); /// ``` #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_ietf_protocol_assignment(&self) -> bool { self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 @@ -644,6 +642,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); /// ``` #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_benchmarking(&self) -> bool { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 @@ -677,6 +676,7 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); /// ``` #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_reserved(&self) -> bool { self.octets()[0] & 240 == 240 && !self.is_broadcast() @@ -1234,6 +1234,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_global(&self) -> bool { match self.multicast_scope() { @@ -1260,83 +1261,37 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 } - /// Returns [`true`] if the address is a unicast link-local address (`fe80::/64`). + /// Returns `true` if the address is a unicast address with link-local scope, + /// as defined in [RFC 4291]. /// - /// A common misconception is to think that "unicast link-local addresses start with - /// `fe80::`", but [IETF RFC 4291] actually defines a stricter format for these addresses: + /// A unicast address has link-local scope if it has the prefix `fe80::/10`, as per [RFC 4291 section 2.4]. + /// Note that this encompasses more addresses than those defined in [RFC 4291 section 2.5.6], + /// which describes "Link-Local IPv6 Unicast Addresses" as having the following stricter format: /// - /// ```no_rust - /// | 10 | - /// | bits | 54 bits | 64 bits | + /// ```text + /// | 10 bits | 54 bits | 64 bits | /// +----------+-------------------------+----------------------------+ /// |1111111010| 0 | interface ID | /// +----------+-------------------------+----------------------------+ /// ``` + /// So while currently the only addresses with link-local scope an application will encounter are all in `fe80::/64`, + /// this might change in the future with the publication of new standards. More addresses in `fe80::/10` could be allocated, + /// and those addresses will have link-local scope. /// - /// This method validates the format defined in the RFC and won't recognize addresses - /// like `fe80:0:0:1::` or `fe81::` as unicast link-local addresses. - /// If you need a less strict validation, use [`Ipv6Addr::is_unicast_link_local()`] instead. - /// - /// # Examples - /// - /// ``` - /// #![feature(ip)] - /// - /// use std::net::Ipv6Addr; - /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local_strict()); - /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); - /// assert!(ip.is_unicast_link_local_strict()); - /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); - /// assert!(!ip.is_unicast_link_local_strict()); - /// assert!(ip.is_unicast_link_local()); - /// - /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); - /// assert!(!ip.is_unicast_link_local_strict()); - /// assert!(ip.is_unicast_link_local()); - /// ``` - /// - /// # See also - /// - /// - [IETF RFC 4291 section 2.5.6] - /// - [RFC 4291 errata 4406] (which has been rejected but provides useful - /// insight) - /// - [`Ipv6Addr::is_unicast_link_local()`] + /// Also note that while [RFC 4291 section 2.5.3] mentions about the [loopback address] (`::1`) that "it is treated as having Link-Local scope", + /// this does not mean that the loopback address actually has link-local scope and this method will return `false` on it. /// - /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 - /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 - /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 - #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] - #[inline] - pub const fn is_unicast_link_local_strict(&self) -> bool { - matches!(self.segments(), [0xfe80, 0, 0, 0, ..]) - } - - /// Returns [`true`] if the address is a unicast link-local address (`fe80::/10`). - /// - /// This method returns [`true`] for addresses in the range reserved by [RFC 4291 section 2.4], - /// i.e. addresses with the following format: - /// - /// ```no_rust - /// | 10 | - /// | bits | 54 bits | 64 bits | - /// +----------+-------------------------+----------------------------+ - /// |1111111010| arbitratry value | interface ID | - /// +----------+-------------------------+----------------------------+ - /// ``` - /// - /// As a result, this method considers addresses such as `fe80:0:0:1::` or `fe81::` to be - /// unicast link-local addresses, whereas [`Ipv6Addr::is_unicast_link_local_strict()`] does not. - /// If you need a strict validation fully compliant with the RFC, use - /// [`Ipv6Addr::is_unicast_link_local_strict()`] instead. + /// [RFC 4291]: https://tools.ietf.org/html/rfc4291 + /// [RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 + /// [RFC 4291 section 2.5.3]: https://tools.ietf.org/html/rfc4291#section-2.5.3 + /// [RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 + /// [loopback address]: Ipv6Addr::LOCALHOST /// /// # Examples /// @@ -1345,30 +1300,19 @@ impl Ipv6Addr { /// /// use std::net::Ipv6Addr; /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); + /// // The loopback address (`::1`) does not actually have link-local scope. + /// assert_eq!(Ipv6Addr::LOCALHOST.is_unicast_link_local(), false); /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 0, 0xffff, 0xffff, 0xffff, 0xffff); - /// assert!(ip.is_unicast_link_local()); + /// // Only addresses in `fe80::/10` have link-local scope. + /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), false); + /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); /// - /// let ip = Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// assert!(!ip.is_unicast_link_local_strict()); - /// - /// let ip = Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0); - /// assert!(ip.is_unicast_link_local()); - /// assert!(!ip.is_unicast_link_local_strict()); + /// // Addresses outside the stricter `fe80::/64` also have link-local scope. + /// assert_eq!(Ipv6Addr::new(0xfe80, 0, 0, 1, 0, 0, 0, 0).is_unicast_link_local(), true); + /// assert_eq!(Ipv6Addr::new(0xfe81, 0, 0, 0, 0, 0, 0, 0).is_unicast_link_local(), true); /// ``` - /// - /// # See also - /// - /// - [IETF RFC 4291 section 2.4] - /// - [RFC 4291 errata 4406] (which has been rejected but provides useful - /// insight) - /// - /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 - /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 @@ -1409,6 +1353,7 @@ impl Ipv6Addr { /// /// [RFC 3879]: https://tools.ietf.org/html/rfc3879 #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_unicast_site_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfec0 @@ -1432,6 +1377,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) @@ -1468,6 +1414,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn is_unicast_global(&self) -> bool { !self.is_multicast() @@ -1494,6 +1441,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn multicast_scope(&self) -> Option<Ipv6MulticastScope> { if self.is_multicast() { @@ -1555,6 +1503,7 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); /// ``` #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + #[unstable(feature = "ip", issue = "27709")] #[inline] pub const fn to_ipv4_mapped(&self) -> Option<Ipv4Addr> { match self.octets() { diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs index ef0d4edc434..05f8dea0b7c 100644 --- a/library/std/src/net/ip/tests.rs +++ b/library/std/src/net/ip/tests.rs @@ -480,7 +480,6 @@ fn ipv6_properties() { let unique_local: u16 = 1 << 2; let global: u16 = 1 << 3; let unicast_link_local: u16 = 1 << 4; - let unicast_link_local_strict: u16 = 1 << 5; let unicast_site_local: u16 = 1 << 6; let unicast_global: u16 = 1 << 7; let documentation: u16 = 1 << 8; @@ -524,11 +523,6 @@ fn ipv6_properties() { } else { assert!(!ip!($s).is_unicast_link_local()); } - if ($mask & unicast_link_local_strict) == unicast_link_local_strict { - assert!(ip!($s).is_unicast_link_local_strict()); - } else { - assert!(!ip!($s).is_unicast_link_local_strict()); - } if ($mask & unicast_site_local) == unicast_site_local { assert!(ip!($s).is_unicast_site_local()); } else { @@ -587,7 +581,6 @@ fn ipv6_properties() { let unique_local: u16 = 1 << 2; let global: u16 = 1 << 3; let unicast_link_local: u16 = 1 << 4; - let unicast_link_local_strict: u16 = 1 << 5; let unicast_site_local: u16 = 1 << 6; let unicast_global: u16 = 1 << 7; let documentation: u16 = 1 << 8; @@ -621,11 +614,7 @@ fn ipv6_properties() { unicast_link_local ); - check!( - "fe80::", - &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local | unicast_link_local_strict - ); + check!("fe80::", &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); check!( "febf:ffff::", @@ -650,7 +639,7 @@ fn ipv6_properties() { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff ], - unicast_link_local | unicast_link_local_strict + unicast_link_local ); check!( @@ -897,9 +886,6 @@ fn ipv6_const() { const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local(); assert!(!IS_UNIQUE_LOCAL); - const IS_UNICAST_LINK_LOCAL_STRICT: bool = IP_ADDRESS.is_unicast_link_local_strict(); - assert!(!IS_UNICAST_LINK_LOCAL_STRICT); - const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local(); assert!(!IS_UNICAST_LINK_LOCAL); diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 9cf51be2836..913c71d4108 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -906,7 +906,7 @@ impl DirBuilderExt for fs::DirBuilder { /// } /// ``` #[unstable(feature = "unix_chroot", issue = "84715")] -#[cfg(not(target_os = "fuchsia"))] +#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))] pub fn chroot<P: AsRef<Path>>(dir: P) -> io::Result<()> { sys::fs::chroot(dir.as_ref()) } diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs index f014a3d7b25..3dc389b7582 100644 --- a/library/std/src/os/unix/process.rs +++ b/library/std/src/os/unix/process.rs @@ -201,22 +201,32 @@ impl CommandExt for process::Command { } } -/// Unix-specific extensions to [`process::ExitStatus`]. +/// Unix-specific extensions to [`process::ExitStatus`] and +/// [`ExitStatusError`](process::ExitStatusError). /// -/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as passed to the -/// `exit` system call or returned by [`ExitStatus::code()`](crate::process::ExitStatus::code). -/// It represents **any wait status**, as returned by one of the `wait` family of system calls. +/// On Unix, `ExitStatus` **does not necessarily represent an exit status**, as +/// passed to the `exit` system call or returned by +/// [`ExitStatus::code()`](crate::process::ExitStatus::code). It represents **any wait status** +/// as returned by one of the `wait` family of system +/// calls. /// -/// This is because a Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but -/// can also represent other kinds of process event. +/// A Unix wait status (a Rust `ExitStatus`) can represent a Unix exit status, but can also +/// represent other kinds of process event. /// /// This trait is sealed: it cannot be implemented outside the standard library. /// This is so that future additional methods are not breaking changes. #[stable(feature = "rust1", since = "1.0.0")] pub trait ExitStatusExt: Sealed { - /// Creates a new `ExitStatus` from the raw underlying integer status value from `wait` + /// Creates a new `ExitStatus` or `ExitStatusError` from the raw underlying integer status + /// value from `wait` /// /// The value should be a **wait status, not an exit status**. + /// + /// # Panics + /// + /// Panics on an attempt to make an `ExitStatusError` from a wait status of `0`. + /// + /// Making an `ExitStatus` always succeds and never panics. #[stable(feature = "exit_status_from", since = "1.12.0")] fn from_raw(raw: i32) -> Self; @@ -278,6 +288,35 @@ impl ExitStatusExt for process::ExitStatus { } } +#[unstable(feature = "exit_status_error", issue = "84908")] +impl ExitStatusExt for process::ExitStatusError { + fn from_raw(raw: i32) -> Self { + process::ExitStatus::from_raw(raw) + .exit_ok() + .expect_err("<ExitStatusError as ExitStatusExt>::from_raw(0) but zero is not an error") + } + + fn signal(&self) -> Option<i32> { + self.into_status().signal() + } + + fn core_dumped(&self) -> bool { + self.into_status().core_dumped() + } + + fn stopped_signal(&self) -> Option<i32> { + self.into_status().stopped_signal() + } + + fn continued(&self) -> bool { + self.into_status().continued() + } + + fn into_raw(self) -> i32 { + self.into_status().into_raw() + } +} + #[stable(feature = "process_extensions", since = "1.2.0")] impl FromRawFd for process::Stdio { #[inline] diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index b10dde42482..9e3880dfd41 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -55,6 +55,7 @@ pub use core::panic::{Location, PanicInfo}; /// See the [`panic!`] macro for more information about panicking. #[stable(feature = "panic_any", since = "1.51.0")] #[inline] +#[track_caller] pub fn panic_any<M: 'static + Any + Send>(msg: M) -> ! { crate::panicking::begin_panic(msg); } diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index a8410bea734..02957e75a74 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -20,7 +20,7 @@ use crate::sync::atomic::{AtomicBool, Ordering}; use crate::sys::stdio::panic_output; use crate::sys_common::backtrace::{self, RustBacktrace}; use crate::sys_common::rwlock::RWLock; -use crate::sys_common::{thread_info, util}; +use crate::sys_common::thread_info; use crate::thread; #[cfg(not(test))] @@ -596,15 +596,12 @@ fn rust_panic_with_hook( if panics > 2 { // Don't try to print the message in this case // - perhaps that is causing the recursive panics. - util::dumb_print(format_args!("thread panicked while processing panic. aborting.\n")); + rtprintpanic!("thread panicked while processing panic. aborting.\n"); } else { // Unfortunately, this does not print a backtrace, because creating // a `Backtrace` will allocate, which we must to avoid here. let panicinfo = PanicInfo::internal_constructor(message, location); - util::dumb_print(format_args!( - "{}\npanicked after panic::always_abort(), aborting.\n", - panicinfo - )); + rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo); } intrinsics::abort() } @@ -637,7 +634,7 @@ fn rust_panic_with_hook( // have limited options. Currently our preference is to // just abort. In the future we may consider resuming // unwinding or otherwise exiting the thread cleanly. - util::dumb_print(format_args!("thread panicked while panicking. aborting.\n")); + rtprintpanic!("thread panicked while panicking. aborting.\n"); intrinsics::abort() } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index cbe14767bd3..9c5615f58c4 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -2507,11 +2507,7 @@ impl Path { #[unstable(feature = "path_try_exists", issue = "83186")] #[inline] pub fn try_exists(&self) -> io::Result<bool> { - match fs::metadata(self) { - Ok(_) => Ok(true), - Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false), - Err(error) => Err(error), - } + fs::try_exists(self) } /// Returns `true` if the path exists on disk and is pointing at a regular file. diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 1b4facdd049..12d52cc8e0b 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -88,9 +88,9 @@ pub mod v1; /// The 2015 version of the prelude of The Rust Standard Library. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2015", issue = "none")] +#[unstable(feature = "prelude_2015", issue = "85684")] pub mod rust_2015 { - #[unstable(feature = "prelude_2015", issue = "none")] + #[unstable(feature = "prelude_2015", issue = "85684")] #[doc(no_inline)] pub use super::v1::*; } @@ -98,9 +98,9 @@ pub mod rust_2015 { /// The 2018 version of the prelude of The Rust Standard Library. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2018", issue = "none")] +#[unstable(feature = "prelude_2018", issue = "85684")] pub mod rust_2018 { - #[unstable(feature = "prelude_2018", issue = "none")] + #[unstable(feature = "prelude_2018", issue = "85684")] #[doc(no_inline)] pub use super::v1::*; } @@ -108,13 +108,13 @@ pub mod rust_2018 { /// The 2021 version of the prelude of The Rust Standard Library. /// /// See the [module-level documentation](self) for more. -#[unstable(feature = "prelude_2021", issue = "none")] +#[unstable(feature = "prelude_2021", issue = "85684")] pub mod rust_2021 { - #[unstable(feature = "prelude_2021", issue = "none")] + #[unstable(feature = "prelude_2021", issue = "85684")] #[doc(no_inline)] pub use super::v1::*; - #[unstable(feature = "prelude_2021", issue = "none")] + #[unstable(feature = "prelude_2021", issue = "85684")] #[doc(no_inline)] pub use core::prelude::rust_2021::*; } diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index 96ab32104ea..8a3e425350a 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -345,6 +345,9 @@ mod prim_never {} mod prim_char {} #[doc(primitive = "unit")] +#[doc(alias = "(")] +#[doc(alias = ")")] +#[doc(alias = "()")] // /// The `()` type, also called "unit". /// @@ -537,8 +540,7 @@ mod prim_pointer {} /// /// # Examples /// -#[cfg_attr(bootstrap, doc = "```ignore")] -#[cfg_attr(not(bootstrap), doc = "```")] +/// ``` /// let mut array: [i32; 3] = [0; 3]; /// /// array[1] = 1; @@ -578,8 +580,7 @@ mod prim_pointer {} /// `IntoIterator` by value. In the future, the behavior on the 2015 and 2018 edition /// might be made consistent to the behavior of later editions. /// -#[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")] -#[cfg_attr(not(bootstrap), doc = "```rust,edition2018")] +/// ```rust,edition2018 /// # #![allow(array_into_iter)] // override our `deny(warnings)` /// let array: [i32; 3] = [0; 3]; /// @@ -634,8 +635,7 @@ mod prim_pointer {} /// * replace `for ... in array.into_iter() {` with `for ... in array {`, /// equivalent to the post-2021 behavior (Rust 1.53+) /// -#[cfg_attr(bootstrap, doc = "```rust,edition2018,ignore")] -#[cfg_attr(not(bootstrap), doc = "```rust,edition2018")] +/// ```rust,edition2018 /// use std::array::IntoIter; /// /// let array: [i32; 3] = [0; 3]; diff --git a/library/std/src/process.rs b/library/std/src/process.rs index b45c620fd0b..6903ba90560 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -110,6 +110,7 @@ use crate::ffi::OsStr; use crate::fmt; use crate::fs; use crate::io::{self, Initializer, IoSlice, IoSliceMut}; +use crate::num::NonZeroI32; use crate::path::Path; use crate::str; use crate::sys::pipe::{read2, AnonPipe}; @@ -1387,8 +1388,8 @@ impl From<fs::File> for Stdio { /// An `ExitStatus` represents every possible disposition of a process. On Unix this /// is the **wait status**. It is *not* simply an *exit status* (a value passed to `exit`). /// -/// For proper error reporting of failed processes, print the value of `ExitStatus` using its -/// implementation of [`Display`](crate::fmt::Display). +/// For proper error reporting of failed processes, print the value of `ExitStatus` or +/// `ExitStatusError` using their implementations of [`Display`](crate::fmt::Display). /// /// [`status`]: Command::status /// [`wait`]: Child::wait @@ -1401,6 +1402,29 @@ pub struct ExitStatus(imp::ExitStatus); impl crate::sealed::Sealed for ExitStatus {} impl ExitStatus { + /// Was termination successful? Returns a `Result`. + /// + /// # Examples + /// + /// ``` + /// #![feature(exit_status_error)] + /// # if cfg!(unix) { + /// use std::process::Command; + /// + /// let status = Command::new("ls") + /// .arg("/dev/nonexistent") + /// .status() + /// .expect("ls could not be executed"); + /// + /// println!("ls: {}", status); + /// status.exit_ok().expect_err("/dev/nonexistent could be listed!"); + /// # } // cfg!(unix) + /// ``` + #[unstable(feature = "exit_status_error", issue = "84908")] + pub fn exit_ok(&self) -> Result<(), ExitStatusError> { + self.0.exit_ok().map_err(ExitStatusError) + } + /// Was termination successful? Signal termination is not considered a /// success, and success is defined as a zero exit status. /// @@ -1422,7 +1446,7 @@ impl ExitStatus { /// ``` #[stable(feature = "process", since = "1.0.0")] pub fn success(&self) -> bool { - self.0.success() + self.0.exit_ok().is_ok() } /// Returns the exit code of the process, if any. @@ -1476,6 +1500,120 @@ impl fmt::Display for ExitStatus { } } +/// Allows extension traits within `std`. +#[unstable(feature = "sealed", issue = "none")] +impl crate::sealed::Sealed for ExitStatusError {} + +/// Describes the result of a process after it has failed +/// +/// Produced by the [`.exit_ok`](ExitStatus::exit_ok) method on [`ExitStatus`]. +/// +/// # Examples +/// +/// ``` +/// #![feature(exit_status_error)] +/// # if cfg!(unix) { +/// use std::process::{Command, ExitStatusError}; +/// +/// fn run(cmd: &str) -> Result<(),ExitStatusError> { +/// Command::new(cmd).status().unwrap().exit_ok()?; +/// Ok(()) +/// } +/// +/// run("true").unwrap(); +/// run("false").unwrap_err(); +/// # } // cfg!(unix) +/// ``` +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[unstable(feature = "exit_status_error", issue = "84908")] +// The definition of imp::ExitStatusError should ideally be such that +// Result<(), imp::ExitStatusError> has an identical representation to imp::ExitStatus. +pub struct ExitStatusError(imp::ExitStatusError); + +#[unstable(feature = "exit_status_error", issue = "84908")] +impl ExitStatusError { + /// Reports the exit code, if applicable, from an `ExitStatusError`. + /// + /// In Unix terms the return value is the **exit status**: the value passed to `exit`, if the + /// process finished by calling `exit`. Note that on Unix the exit status is truncated to 8 + /// bits, and that values that didn't come from a program's call to `exit` may be invented by the + /// runtime system (often, for example, 255, 254, 127 or 126). + /// + /// On Unix, this will return `None` if the process was terminated by a signal. If you want to + /// handle such situations specially, consider using methods from + /// [`ExitStatusExt`](crate::os::unix::process::ExitStatusExt). + /// + /// If the process finished by calling `exit` with a nonzero value, this will return + /// that exit status. + /// + /// If the error was something else, it will return `None`. + /// + /// If the process exited successfully (ie, by calling `exit(0)`), there is no + /// `ExitStatusError`. So the return value from `ExitStatusError::code()` is always nonzero. + /// + /// # Examples + /// + /// ``` + /// #![feature(exit_status_error)] + /// # #[cfg(unix)] { + /// use std::process::Command; + /// + /// let bad = Command::new("false").status().unwrap().exit_ok().unwrap_err(); + /// assert_eq!(bad.code(), Some(1)); + /// # } // #[cfg(unix)] + /// ``` + pub fn code(&self) -> Option<i32> { + self.code_nonzero().map(Into::into) + } + + /// Reports the exit code, if applicable, from an `ExitStatusError`, as a `NonZero` + /// + /// This is exaclty like [`code()`](Self::code), except that it returns a `NonZeroI32`. + /// + /// Plain `code`, returning a plain integer, is provided because is is often more convenient. + /// The returned value from `code()` is indeed also nonzero; use `code_nonzero()` when you want + /// a type-level guarantee of nonzeroness. + /// + /// # Examples + /// + /// ``` + /// #![feature(exit_status_error)] + /// # if cfg!(unix) { + /// use std::convert::TryFrom; + /// use std::num::NonZeroI32; + /// use std::process::Command; + /// + /// let bad = Command::new("false").status().unwrap().exit_ok().unwrap_err(); + /// assert_eq!(bad.code_nonzero().unwrap(), NonZeroI32::try_from(1).unwrap()); + /// # } // cfg!(unix) + /// ``` + pub fn code_nonzero(&self) -> Option<NonZeroI32> { + self.0.code() + } + + /// Converts an `ExitStatusError` (back) to an `ExitStatus`. + pub fn into_status(&self) -> ExitStatus { + ExitStatus(self.0.into()) + } +} + +#[unstable(feature = "exit_status_error", issue = "84908")] +impl Into<ExitStatus> for ExitStatusError { + fn into(self) -> ExitStatus { + ExitStatus(self.0.into()) + } +} + +#[unstable(feature = "exit_status_error", issue = "84908")] +impl fmt::Display for ExitStatusError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "process exited unsuccessfully: {}", self.into_status()) + } +} + +#[unstable(feature = "exit_status_error", issue = "84908")] +impl crate::error::Error for ExitStatusError {} + /// This type represents the status code a process can return to its /// parent under normal termination. /// diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index 773ab18b2ce..e7c5479ab9b 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -294,8 +294,14 @@ impl<T: ?Sized> Mutex<T> { /// # Errors /// /// If another user of this mutex panicked while holding the mutex, then - /// this call will return an error if the mutex would otherwise be - /// acquired. + /// this call will return the [`Poisoned`] error if the mutex would + /// otherwise be acquired. + /// + /// If the mutex could not be acquired because it is already locked, then + /// this call will return the [`WouldBlock`] error. + /// + /// [`Poisoned`]: TryLockError::Poisoned + /// [`WouldBlock`]: TryLockError::WouldBlock /// /// # Examples /// diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index b01bcec1361..9d521ab14cb 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -199,11 +199,17 @@ impl<T: ?Sized> RwLock<T> { /// /// # Errors /// - /// This function will return an error if the RwLock is poisoned. An RwLock - /// is poisoned whenever a writer panics while holding an exclusive lock. An - /// error will only be returned if the lock would have otherwise been + /// This function will return the [`Poisoned`] error if the RwLock is poisoned. + /// An RwLock is poisoned whenever a writer panics while holding an exclusive + /// lock. `Poisoned` will only be returned if the lock would have otherwise been /// acquired. /// + /// This function will return the [`WouldBlock`] error if the RwLock could not + /// be acquired because it was already locked exclusively. + /// + /// [`Poisoned`]: TryLockError::Poisoned + /// [`WouldBlock`]: TryLockError::WouldBlock + /// /// # Examples /// /// ``` @@ -281,10 +287,17 @@ impl<T: ?Sized> RwLock<T> { /// /// # Errors /// - /// This function will return an error if the RwLock is poisoned. An RwLock - /// is poisoned whenever a writer panics while holding an exclusive lock. An - /// error will only be returned if the lock would have otherwise been - /// acquired. + /// This function will return the [`Poisoned`] error if the RwLock is + /// poisoned. An RwLock is poisoned whenever a writer panics while holding + /// an exclusive lock. `Poisoned` will only be returned if the lock would have + /// otherwise been acquired. + /// + /// This function will return the [`WouldBlock`] error if the RwLock could not + /// be acquired because it was already locked exclusively. + /// + /// [`Poisoned`]: TryLockError::Poisoned + /// [`WouldBlock`]: TryLockError::WouldBlock + /// /// /// # Examples /// diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs index 5b3f2fa4e82..76ea70d997f 100644 --- a/library/std/src/sys/hermit/fs.rs +++ b/library/std/src/sys/hermit/fs.rs @@ -12,7 +12,7 @@ use crate::sys::time::SystemTime; use crate::sys::unsupported; use crate::sys_common::os_str_bytes::OsStrExt; -pub use crate::sys_common::fs::copy; +pub use crate::sys_common::fs::{copy, try_exists}; //pub use crate::sys_common::fs::remove_dir_all; fn cstr(path: &Path) -> io::Result<CString> { diff --git a/library/std/src/sys/hermit/os.rs b/library/std/src/sys/hermit/os.rs index 81cd68a74e6..40bd393098f 100644 --- a/library/std/src/sys/hermit/os.rs +++ b/library/std/src/sys/hermit/os.rs @@ -4,11 +4,11 @@ use crate::ffi::{CStr, OsStr, OsString}; use crate::fmt; use crate::io; use crate::marker::PhantomData; -use crate::memchr; use crate::path::{self, PathBuf}; use crate::str; use crate::sync::Mutex; use crate::sys::hermit::abi; +use crate::sys::memchr; use crate::sys::unsupported; use crate::sys_common::os_str_bytes::*; use crate::vec; diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 79617aa77b7..f8ca67c844c 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -48,7 +48,7 @@ use libc::{ dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, readdir64_r, stat64, }; -pub use crate::sys_common::fs::remove_dir_all; +pub use crate::sys_common::fs::{remove_dir_all, try_exists}; pub struct File(FileDesc); @@ -1329,7 +1329,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { Ok(bytes_copied as u64) } -#[cfg(not(target_os = "fuchsia"))] +#[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))] pub fn chroot(dir: &Path) -> io::Result<()> { let dir = cstr(dir)?; cvt(unsafe { libc::chroot(dir.as_ptr()) })?; diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index 57d91441b6f..ca9cc8ca7ba 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -210,7 +210,6 @@ cfg_if::cfg_if! { if #[cfg(target_os = "android")] { #[link(name = "dl")] #[link(name = "log")] - #[link(name = "gcc")] extern "C" {} } else if #[cfg(target_os = "freebsd")] { #[link(name = "execinfo")] diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs index e6b61062d15..d5a15964c08 100644 --- a/library/std/src/sys/unix/net.rs +++ b/library/std/src/sys/unix/net.rs @@ -62,7 +62,7 @@ impl Socket { target_os = "illumos", target_os = "linux", target_os = "netbsd", - target_os = "opensbd", + target_os = "openbsd", ))] { // On platforms that support it we pass the SOCK_CLOEXEC // flag to atomically create the socket and set it as @@ -99,7 +99,7 @@ impl Socket { target_os = "illumos", target_os = "linux", target_os = "netbsd", - target_os = "opensbd", + target_os = "openbsd", ))] { // Like above, set cloexec atomically cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?; @@ -204,7 +204,7 @@ impl Socket { target_os = "illumos", target_os = "linux", target_os = "netbsd", - target_os = "opensbd", + target_os = "openbsd", ))] { let fd = cvt_r(|| unsafe { libc::accept4(self.0.raw(), storage, len, libc::SOCK_CLOEXEC) diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 51c3e5d175c..bbc4691d963 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -13,13 +13,13 @@ use crate::fmt; use crate::io; use crate::iter; use crate::mem; -use crate::memchr; use crate::path::{self, PathBuf}; use crate::ptr; use crate::slice; use crate::str; use crate::sys::cvt; use crate::sys::fd; +use crate::sys::memchr; use crate::sys::rwlock::{RWLockReadGuard, StaticRWLock}; use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; use crate::vec; diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs index f67c70c0177..b5a19ed54a2 100644 --- a/library/std/src/sys/unix/process/mod.rs +++ b/library/std/src/sys/unix/process/mod.rs @@ -1,5 +1,5 @@ pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; -pub use self::process_inner::{ExitStatus, Process}; +pub use self::process_inner::{ExitStatus, ExitStatusError, Process}; pub use crate::ffi::OsString as EnvKey; pub use crate::sys_common::process::CommandEnvs; diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index b19ad4ccdc7..507abb27871 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -1,7 +1,8 @@ -use crate::convert::TryInto; +use crate::convert::{TryFrom, TryInto}; use crate::fmt; use crate::io; use crate::mem; +use crate::num::{NonZeroI32, NonZeroI64}; use crate::ptr; use crate::sys::process::process_common::*; @@ -236,8 +237,11 @@ impl Process { pub struct ExitStatus(i64); impl ExitStatus { - pub fn success(&self) -> bool { - self.code() == Some(0) + pub fn exit_ok(&self) -> Result<(), ExitStatusError> { + match NonZeroI64::try_from(self.0) { + /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)), + /* was zero, couldn't convert */ Err(_) => Ok(()), + } } pub fn code(&self) -> Option<i32> { @@ -306,3 +310,19 @@ impl fmt::Display for ExitStatus { write!(f, "exit code: {}", self.0) } } + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatusError(NonZeroI64); + +impl Into<ExitStatus> for ExitStatusError { + fn into(self) -> ExitStatus { + ExitStatus(self.0.into()) + } +} + +impl ExitStatusError { + pub fn code(self) -> Option<NonZeroI32> { + // fixme: affected by the same bug as ExitStatus::code() + ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap()) + } +} diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 08b500b9c82..ed55e1aa715 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -1,7 +1,9 @@ -use crate::convert::TryInto; +use crate::convert::{TryFrom, TryInto}; use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::mem; +use crate::num::NonZeroI32; +use crate::os::raw::NonZero_c_int; use crate::ptr; use crate::sys; use crate::sys::cvt; @@ -491,8 +493,16 @@ impl ExitStatus { libc::WIFEXITED(self.0) } - pub fn success(&self) -> bool { - self.code() == Some(0) + pub fn exit_ok(&self) -> Result<(), ExitStatusError> { + // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is + // true on all actual versions of Unix, is widely assumed, and is specified in SuS + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html . If it is not + // true for a platform pretending to be Unix, the tests (our doctests, and also + // procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. + match NonZero_c_int::try_from(self.0) { + /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)), + /* was zero, couldn't convert */ Err(_) => Ok(()), + } } pub fn code(&self) -> Option<i32> { @@ -547,6 +557,21 @@ impl fmt::Display for ExitStatus { } } +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatusError(NonZero_c_int); + +impl Into<ExitStatus> for ExitStatusError { + fn into(self) -> ExitStatus { + ExitStatus(self.0.into()) + } +} + +impl ExitStatusError { + pub fn code(self) -> Option<NonZeroI32> { + ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap()) + } +} + #[cfg(test)] #[path = "process_unix/tests.rs"] mod tests; diff --git a/library/std/src/sys/unix/process/process_vxworks.rs b/library/std/src/sys/unix/process/process_vxworks.rs index eecdb624b9c..c17822f5125 100644 --- a/library/std/src/sys/unix/process/process_vxworks.rs +++ b/library/std/src/sys/unix/process/process_vxworks.rs @@ -1,5 +1,8 @@ +use crate::convert::{TryFrom, TryInto}; use crate::fmt; use crate::io::{self, Error, ErrorKind}; +use crate::num::NonZeroI32; +use crate::os::raw::NonZero_c_int; use crate::sys; use crate::sys::cvt; use crate::sys::process::process_common::*; @@ -187,8 +190,16 @@ impl ExitStatus { libc::WIFEXITED(self.0) } - pub fn success(&self) -> bool { - self.code() == Some(0) + pub fn exit_ok(&self) -> Result<(), ExitStatusError> { + // This assumes that WIFEXITED(status) && WEXITSTATUS==0 corresponds to status==0. This is + // true on all actual versions of Unix, is widely assumed, and is specified in SuS + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/wait.html . If it is not + // true for a platform pretending to be Unix, the tests (our doctests, and also + // procsss_unix/tests.rs) will spot it. `ExitStatusError::code` assumes this too. + match NonZero_c_int::try_from(self.0) { + Ok(failure) => Err(ExitStatusError(failure)), + Err(_) => Ok(()), + } } pub fn code(&self) -> Option<i32> { @@ -235,3 +246,18 @@ impl fmt::Display for ExitStatus { } } } + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatusError(NonZero_c_int); + +impl Into<ExitStatus> for ExitStatusError { + fn into(self) -> ExitStatus { + ExitStatus(self.0.into()) + } +} + +impl ExitStatusError { + pub fn code(self) -> Option<NonZeroI32> { + ExitStatus(self.0.into()).code().map(|st| st.try_into().unwrap()) + } +} diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs index 2a487fff54a..81f47a779d3 100644 --- a/library/std/src/sys/unix/stack_overflow.rs +++ b/library/std/src/sys/unix/stack_overflow.rs @@ -42,6 +42,7 @@ mod imp { use crate::io; use crate::mem; use crate::ptr; + use crate::thread; use libc::MAP_FAILED; use libc::{mmap, munmap}; @@ -95,15 +96,16 @@ mod imp { info: *mut libc::siginfo_t, _data: *mut libc::c_void, ) { - use crate::sys_common::util::report_overflow; - let guard = thread_info::stack_guard().unwrap_or(0..0); let addr = siginfo_si_addr(info); // If the faulting address is within the guard page, then we print a // message saying so and abort. if guard.start <= addr && addr < guard.end { - report_overflow(); + rtprintpanic!( + "\nthread '{}' has overflowed its stack\n", + thread::current().name().unwrap_or("<unknown>") + ); rtabort!("stack overflow"); } else { // Unregister ourselves by reverting back to the default behavior. diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs index cd533761e37..6b45e29c145 100644 --- a/library/std/src/sys/unsupported/fs.rs +++ b/library/std/src/sys/unsupported/fs.rs @@ -275,6 +275,10 @@ pub fn remove_dir_all(_path: &Path) -> io::Result<()> { unsupported() } +pub fn try_exists(_path: &Path) -> io::Result<bool> { + unsupported() +} + pub fn readlink(_p: &Path) -> io::Result<PathBuf> { unsupported() } diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 38ac0a1ddd5..7846e43cfb5 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -2,6 +2,7 @@ use crate::ffi::OsStr; use crate::fmt; use crate::io; use crate::marker::PhantomData; +use crate::num::NonZeroI32; use crate::path::Path; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; @@ -97,7 +98,7 @@ impl fmt::Debug for Command { pub struct ExitStatus(!); impl ExitStatus { - pub fn success(&self) -> bool { + pub fn exit_ok(&self) -> Result<(), ExitStatusError> { self.0 } @@ -135,6 +136,21 @@ impl fmt::Display for ExitStatus { } #[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatusError(ExitStatus); + +impl Into<ExitStatus> for ExitStatusError { + fn into(self) -> ExitStatus { + self.0.0 + } +} + +impl ExitStatusError { + pub fn code(self) -> Option<NonZeroI32> { + self.0.0 + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct ExitCode(bool); impl ExitCode { diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index ed0f03e4b71..45e38f68b8c 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -14,7 +14,7 @@ use crate::sys::time::SystemTime; use crate::sys::unsupported; use crate::sys_common::FromInner; -pub use crate::sys_common::fs::remove_dir_all; +pub use crate::sys_common::fs::{remove_dir_all, try_exists}; pub struct File { fd: WasiFd, diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index 7ea6048e94a..b7efc884473 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -4,6 +4,7 @@ #![cfg_attr(test, allow(dead_code))] #![unstable(issue = "none", feature = "windows_c")] +use crate::os::raw::NonZero_c_ulong; use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort}; use crate::ptr; @@ -13,6 +14,7 @@ pub use self::EXCEPTION_DISPOSITION::*; pub use self::FILE_INFO_BY_HANDLE_CLASS::*; pub type DWORD = c_ulong; +pub type NonZeroDWORD = NonZero_c_ulong; pub type HANDLE = LPVOID; pub type HINSTANCE = HANDLE; pub type HMODULE = HINSTANCE; @@ -171,6 +173,7 @@ pub const ERROR_INVALID_HANDLE: DWORD = 6; pub const ERROR_NOT_ENOUGH_MEMORY: DWORD = 8; pub const ERROR_OUTOFMEMORY: DWORD = 14; pub const ERROR_NO_MORE_FILES: DWORD = 18; +pub const ERROR_SHARING_VIOLATION: u32 = 32; pub const ERROR_HANDLE_EOF: DWORD = 38; pub const ERROR_FILE_EXISTS: DWORD = 80; pub const ERROR_INVALID_PARAMETER: DWORD = 87; @@ -628,7 +631,7 @@ pub struct timeval { pub tv_usec: c_long, } -// Functions forbidden when targeting UWP +// Desktop specific functions & types cfg_if::cfg_if! { if #[cfg(not(target_vendor = "uwp"))] { pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; @@ -642,7 +645,7 @@ if #[cfg(not(target_vendor = "uwp"))] { pub ExceptionRecord: *mut EXCEPTION_RECORD, pub ExceptionAddress: LPVOID, pub NumberParameters: DWORD, - pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS] + pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS], } pub enum CONTEXT {} @@ -653,8 +656,8 @@ if #[cfg(not(target_vendor = "uwp"))] { pub ContextRecord: *mut CONTEXT, } - pub type PVECTORED_EXCEPTION_HANDLER = extern "system" - fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG; + pub type PVECTORED_EXCEPTION_HANDLER = + extern "system" fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG; #[repr(C)] #[derive(Copy, Clone)] @@ -688,44 +691,66 @@ if #[cfg(not(target_vendor = "uwp"))] { pub const TOKEN_READ: DWORD = 0x20008; + #[link(name = "advapi32")] extern "system" { + // Forbidden when targeting UWP #[link_name = "SystemFunction036"] pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN; - pub fn ReadConsoleW(hConsoleInput: HANDLE, - lpBuffer: LPVOID, - nNumberOfCharsToRead: DWORD, - lpNumberOfCharsRead: LPDWORD, - pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL; + // Allowed but unused by UWP + pub fn OpenProcessToken( + ProcessHandle: HANDLE, + DesiredAccess: DWORD, + TokenHandle: *mut HANDLE, + ) -> BOOL; + } - pub fn WriteConsoleW(hConsoleOutput: HANDLE, - lpBuffer: LPCVOID, - nNumberOfCharsToWrite: DWORD, - lpNumberOfCharsWritten: LPDWORD, - lpReserved: LPVOID) -> BOOL; + #[link(name = "userenv")] + extern "system" { + // Allowed but unused by UWP + pub fn GetUserProfileDirectoryW( + hToken: HANDLE, + lpProfileDir: LPWSTR, + lpcchSize: *mut DWORD, + ) -> BOOL; + } - pub fn GetConsoleMode(hConsoleHandle: HANDLE, - lpMode: LPDWORD) -> BOOL; + #[link(name = "kernel32")] + extern "system" { + // Functions forbidden when targeting UWP + pub fn ReadConsoleW( + hConsoleInput: HANDLE, + lpBuffer: LPVOID, + nNumberOfCharsToRead: DWORD, + lpNumberOfCharsRead: LPDWORD, + pInputControl: PCONSOLE_READCONSOLE_CONTROL, + ) -> BOOL; + + pub fn WriteConsoleW( + hConsoleOutput: HANDLE, + lpBuffer: LPCVOID, + nNumberOfCharsToWrite: DWORD, + lpNumberOfCharsWritten: LPDWORD, + lpReserved: LPVOID, + ) -> BOOL; + + pub fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL; // Allowed but unused by UWP - pub fn OpenProcessToken(ProcessHandle: HANDLE, - DesiredAccess: DWORD, - TokenHandle: *mut HANDLE) -> BOOL; - pub fn GetUserProfileDirectoryW(hToken: HANDLE, - lpProfileDir: LPWSTR, - lpcchSize: *mut DWORD) -> BOOL; - pub fn GetFileInformationByHandle(hFile: HANDLE, - lpFileInformation: LPBY_HANDLE_FILE_INFORMATION) - -> BOOL; - pub fn SetHandleInformation(hObject: HANDLE, - dwMask: DWORD, - dwFlags: DWORD) -> BOOL; - pub fn AddVectoredExceptionHandler(FirstHandler: ULONG, - VectoredHandler: PVECTORED_EXCEPTION_HANDLER) - -> LPVOID; - pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR, - lpTargetFileName: LPCWSTR, - lpSecurityAttributes: LPSECURITY_ATTRIBUTES) - -> BOOL; + pub fn GetFileInformationByHandle( + hFile: HANDLE, + lpFileInformation: LPBY_HANDLE_FILE_INFORMATION, + ) -> BOOL; + pub fn SetHandleInformation(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) -> BOOL; + pub fn AddVectoredExceptionHandler( + FirstHandler: ULONG, + VectoredHandler: PVECTORED_EXCEPTION_HANDLER, + ) -> LPVOID; + pub fn CreateHardLinkW( + lpSymlinkFileName: LPCWSTR, + lpTargetFileName: LPCWSTR, + lpSecurityAttributes: LPSECURITY_ATTRIBUTES, + ) -> BOOL; + pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL; } } } @@ -744,55 +769,32 @@ if #[cfg(target_vendor = "uwp")] { pub Directory: BOOLEAN, } + #[link(name = "bcrypt")] extern "system" { - pub fn GetFileInformationByHandleEx(hFile: HANDLE, - fileInfoClass: FILE_INFO_BY_HANDLE_CLASS, - lpFileInformation: LPVOID, - dwBufferSize: DWORD) -> BOOL; - pub fn BCryptGenRandom(hAlgorithm: LPVOID, pBuffer: *mut u8, - cbBuffer: ULONG, dwFlags: ULONG) -> LONG; + pub fn BCryptGenRandom( + hAlgorithm: LPVOID, + pBuffer: *mut u8, + cbBuffer: ULONG, + dwFlags: ULONG, + ) -> LONG; + } + #[link(name = "kernel32")] + extern "system" { + pub fn GetFileInformationByHandleEx( + hFile: HANDLE, + fileInfoClass: FILE_INFO_BY_HANDLE_CLASS, + lpFileInformation: LPVOID, + dwBufferSize: DWORD, + ) -> BOOL; } } } // Shared between Desktop & UWP + +#[link(name = "kernel32")] extern "system" { - pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int; - pub fn WSACleanup() -> c_int; - pub fn WSAGetLastError() -> c_int; - pub fn WSADuplicateSocketW( - s: SOCKET, - dwProcessId: DWORD, - lpProtocolInfo: LPWSAPROTOCOL_INFO, - ) -> c_int; - pub fn WSASend( - s: SOCKET, - lpBuffers: LPWSABUF, - dwBufferCount: DWORD, - lpNumberOfBytesSent: LPDWORD, - dwFlags: DWORD, - lpOverlapped: LPWSAOVERLAPPED, - lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, - ) -> c_int; - pub fn WSARecv( - s: SOCKET, - lpBuffers: LPWSABUF, - dwBufferCount: DWORD, - lpNumberOfBytesRecvd: LPDWORD, - lpFlags: LPDWORD, - lpOverlapped: LPWSAOVERLAPPED, - lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, - ) -> c_int; pub fn GetCurrentProcessId() -> DWORD; - pub fn WSASocketW( - af: c_int, - kind: c_int, - protocol: c_int, - lpProtocolInfo: LPWSAPROTOCOL_INFO, - g: GROUP, - dwFlags: DWORD, - ) -> SOCKET; - pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int; pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL; @@ -879,28 +881,6 @@ extern "system" { pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL; pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD; pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL; - - pub fn closesocket(socket: SOCKET) -> c_int; - pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int; - pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int; - pub fn recvfrom( - socket: SOCKET, - buf: *mut c_void, - len: c_int, - flags: c_int, - addr: *mut SOCKADDR, - addrlen: *mut c_int, - ) -> c_int; - pub fn sendto( - socket: SOCKET, - buf: *const c_void, - len: c_int, - flags: c_int, - addr: *const SOCKADDR, - addrlen: c_int, - ) -> c_int; - pub fn shutdown(socket: SOCKET, how: c_int) -> c_int; - pub fn accept(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET; pub fn DuplicateHandle( hSourceProcessHandle: HANDLE, hSourceHandle: HANDLE, @@ -947,32 +927,6 @@ extern "system" { pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE; pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL; pub fn FindClose(findFile: HANDLE) -> BOOL; - pub fn getsockopt( - s: SOCKET, - level: c_int, - optname: c_int, - optval: *mut c_char, - optlen: *mut c_int, - ) -> c_int; - pub fn setsockopt( - s: SOCKET, - level: c_int, - optname: c_int, - optval: *const c_void, - optlen: c_int, - ) -> c_int; - pub fn getsockname(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int; - pub fn getpeername(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int; - pub fn bind(socket: SOCKET, address: *const SOCKADDR, address_len: socklen_t) -> c_int; - pub fn listen(socket: SOCKET, backlog: c_int) -> c_int; - pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int; - pub fn getaddrinfo( - node: *const c_char, - service: *const c_char, - hints: *const ADDRINFOA, - res: *mut *mut ADDRINFOA, - ) -> c_int; - pub fn freeaddrinfo(res: *mut ADDRINFOA); pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void; pub fn GetModuleHandleA(lpModuleName: LPCSTR) -> HMODULE; @@ -1009,47 +963,23 @@ extern "system" { lpNumberOfBytesTransferred: LPDWORD, bWait: BOOL, ) -> BOOL; - pub fn select( - nfds: c_int, - readfds: *mut fd_set, - writefds: *mut fd_set, - exceptfds: *mut fd_set, - timeout: *const timeval, - ) -> c_int; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw pub fn CreateSymbolicLinkW( lpSymlinkFileName: LPCWSTR, lpTargetFileName: LPCWSTR, dwFlags: DWORD, ) -> BOOLEAN; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew pub fn GetFinalPathNameByHandleW( hFile: HANDLE, lpszFilePath: LPCWSTR, cchFilePath: DWORD, dwFlags: DWORD, ) -> DWORD; - - // >= Vista / Server 2003 - // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadstackguarantee - #[cfg(not(target_vendor = "uwp"))] - pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle pub fn SetFileInformationByHandle( hFile: HANDLE, FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, lpFileInformation: LPVOID, dwBufferSize: DWORD, ) -> BOOL; - - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleepconditionvariablesrw pub fn SleepConditionVariableSRW( ConditionVariable: PCONDITION_VARIABLE, SRWLock: PSRWLOCK, @@ -1057,13 +987,9 @@ extern "system" { Flags: ULONG, ) -> BOOL; - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakeconditionvariable pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE); pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE); - // >= Vista / Server 2008 - // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-acquiresrwlockexclusive pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK); pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK); pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK); @@ -1072,6 +998,99 @@ extern "system" { pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN; } +#[link(name = "ws2_32")] +extern "system" { + pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int; + pub fn WSACleanup() -> c_int; + pub fn WSAGetLastError() -> c_int; + pub fn WSADuplicateSocketW( + s: SOCKET, + dwProcessId: DWORD, + lpProtocolInfo: LPWSAPROTOCOL_INFO, + ) -> c_int; + pub fn WSASend( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesSent: LPDWORD, + dwFlags: DWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int; + pub fn WSARecv( + s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesRecvd: LPDWORD, + lpFlags: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE, + ) -> c_int; + pub fn WSASocketW( + af: c_int, + kind: c_int, + protocol: c_int, + lpProtocolInfo: LPWSAPROTOCOL_INFO, + g: GROUP, + dwFlags: DWORD, + ) -> SOCKET; + pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int; + pub fn closesocket(socket: SOCKET) -> c_int; + pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int; + pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int; + pub fn recvfrom( + socket: SOCKET, + buf: *mut c_void, + len: c_int, + flags: c_int, + addr: *mut SOCKADDR, + addrlen: *mut c_int, + ) -> c_int; + pub fn sendto( + socket: SOCKET, + buf: *const c_void, + len: c_int, + flags: c_int, + addr: *const SOCKADDR, + addrlen: c_int, + ) -> c_int; + pub fn shutdown(socket: SOCKET, how: c_int) -> c_int; + pub fn accept(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET; + pub fn getsockopt( + s: SOCKET, + level: c_int, + optname: c_int, + optval: *mut c_char, + optlen: *mut c_int, + ) -> c_int; + pub fn setsockopt( + s: SOCKET, + level: c_int, + optname: c_int, + optval: *const c_void, + optlen: c_int, + ) -> c_int; + pub fn getsockname(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int; + pub fn getpeername(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int; + pub fn bind(socket: SOCKET, address: *const SOCKADDR, address_len: socklen_t) -> c_int; + pub fn listen(socket: SOCKET, backlog: c_int) -> c_int; + pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int; + pub fn getaddrinfo( + node: *const c_char, + service: *const c_char, + hints: *const ADDRINFOA, + res: *mut *mut ADDRINFOA, + ) -> c_int; + pub fn freeaddrinfo(res: *mut ADDRINFOA); + pub fn select( + nfds: c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + exceptfds: *mut fd_set, + timeout: *const timeval, + ) -> c_int; +} + // Functions that aren't available on every version of Windows that we support, // but we still use them and just provide some form of a fallback implementation. compat_fn! { diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index 8e6bd76f85f..2b6143de960 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -944,3 +944,32 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> { .map(drop) } } + +// Try to see if a file exists but, unlike `exists`, report I/O errors. +pub fn try_exists(path: &Path) -> io::Result<bool> { + // Open the file to ensure any symlinks are followed to their target. + let mut opts = OpenOptions::new(); + // No read, write, etc access rights are needed. + opts.access_mode(0); + // Backup semantics enables opening directories as well as files. + opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS); + match File::open(path, &opts) { + Err(e) => match e.kind() { + // The file definitely does not exist + io::ErrorKind::NotFound => Ok(false), + + // `ERROR_SHARING_VIOLATION` means that the file has been locked by + // another process. This is often temporary so we simply report it + // as the file existing. + io::ErrorKind::Other if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as i32) => { + Ok(true) + } + // Other errors such as `ERROR_ACCESS_DENIED` may indicate that the + // file exists. However, these types of errors are usually more + // permanent so we report them here. + _ => Err(e), + }, + // The file was opened successfully therefore it must exist, + Ok(_) => Ok(true), + } +} diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index cc60ca375ea..f23e874f249 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -281,17 +281,3 @@ pub fn abort_internal() -> ! { } crate::intrinsics::abort(); } - -cfg_if::cfg_if! { - if #[cfg(target_vendor = "uwp")] { - #[link(name = "ws2_32")] - // For BCryptGenRandom - #[link(name = "bcrypt")] - extern "C" {} - } else { - #[link(name = "advapi32")] - #[link(name = "ws2_32")] - #[link(name = "userenv")] - extern "C" {} - } -} diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index a5799606142..81dbea4a067 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -5,6 +5,7 @@ mod tests; use crate::borrow::Borrow; use crate::collections::BTreeMap; +use crate::convert::{TryFrom, TryInto}; use crate::env; use crate::env::split_paths; use crate::ffi::{OsStr, OsString}; @@ -12,10 +13,12 @@ use crate::fmt; use crate::fs; use crate::io::{self, Error, ErrorKind}; use crate::mem; +use crate::num::NonZeroI32; use crate::os::windows::ffi::OsStrExt; use crate::path::Path; use crate::ptr; use crate::sys::c; +use crate::sys::c::NonZeroDWORD; use crate::sys::cvt; use crate::sys::fs::{File, OpenOptions}; use crate::sys::handle::Handle; @@ -376,8 +379,11 @@ impl Process { pub struct ExitStatus(c::DWORD); impl ExitStatus { - pub fn success(&self) -> bool { - self.0 == 0 + pub fn exit_ok(&self) -> Result<(), ExitStatusError> { + match NonZeroDWORD::try_from(self.0) { + /* was nonzero */ Ok(failure) => Err(ExitStatusError(failure)), + /* was zero, couldn't convert */ Err(_) => Ok(()), + } } pub fn code(&self) -> Option<i32> { Some(self.0 as i32) @@ -407,6 +413,21 @@ impl fmt::Display for ExitStatus { } #[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitStatusError(c::NonZeroDWORD); + +impl Into<ExitStatus> for ExitStatusError { + fn into(self) -> ExitStatus { + ExitStatus(self.0.into()) + } +} + +impl ExitStatusError { + pub fn code(self) -> Option<NonZeroI32> { + Some((u32::from(self.0) as i32).try_into().unwrap()) + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] pub struct ExitCode(c::DWORD); impl ExitCode { diff --git a/library/std/src/sys/windows/stack_overflow.rs b/library/std/src/sys/windows/stack_overflow.rs index 39efb778207..755dc0a6c8b 100644 --- a/library/std/src/sys/windows/stack_overflow.rs +++ b/library/std/src/sys/windows/stack_overflow.rs @@ -1,7 +1,7 @@ #![cfg_attr(test, allow(dead_code))] use crate::sys::c; -use crate::sys_common::util::report_overflow; +use crate::thread; pub struct Handler; @@ -24,7 +24,10 @@ extern "system" fn vectored_handler(ExceptionInfo: *mut c::EXCEPTION_POINTERS) - let code = rec.ExceptionCode; if code == c::EXCEPTION_STACK_OVERFLOW { - report_overflow(); + rtprintpanic!( + "\nthread '{}' has overflowed its stack\n", + thread::current().name().unwrap_or("<unknown>") + ); } c::EXCEPTION_CONTINUE_SEARCH } diff --git a/library/std/src/sys_common/fs.rs b/library/std/src/sys_common/fs.rs index 30908824dd6..309f5483874 100644 --- a/library/std/src/sys_common/fs.rs +++ b/library/std/src/sys_common/fs.rs @@ -41,3 +41,11 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { } fs::remove_dir(path) } + +pub fn try_exists(path: &Path) -> io::Result<bool> { + match fs::metadata(path) { + Ok(_) => Ok(true), + Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false), + Err(error) => Err(error), + } +} diff --git a/library/std/src/memchr.rs b/library/std/src/sys_common/memchr.rs index 86a08f75a8d..b219e878912 100644 --- a/library/std/src/memchr.rs +++ b/library/std/src/sys_common/memchr.rs @@ -1,6 +1,8 @@ // Original implementation taken from rust-memchr. // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch +use crate::sys::memchr as sys; + #[cfg(test)] mod tests; @@ -25,7 +27,7 @@ mod tests; /// ``` #[inline] pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> { - crate::sys::memchr::memchr(needle, haystack) + sys::memchr(needle, haystack) } /// A safe interface to `memrchr`. @@ -45,5 +47,5 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> { /// ``` #[inline] pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> { - crate::sys::memchr::memrchr(needle, haystack) + sys::memrchr(needle, haystack) } diff --git a/library/std/src/memchr/tests.rs b/library/std/src/sys_common/memchr/tests.rs index 557d749c7f6..557d749c7f6 100644 --- a/library/std/src/memchr/tests.rs +++ b/library/std/src/sys_common/memchr/tests.rs diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 7fa6977f2af..1a9caa22c92 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -25,6 +25,7 @@ pub mod bytestring; pub mod condvar; pub mod fs; pub mod io; +pub mod memchr; pub mod mutex; // `doc` is required because `sys/mod.rs` imports `unix/ext/mod.rs` on Windows // when generating documentation. @@ -40,7 +41,6 @@ pub mod thread_info; pub mod thread_local_dtor; pub mod thread_local_key; pub mod thread_parker; -pub mod util; pub mod wtf8; cfg_if::cfg_if! { diff --git a/library/std/src/sys_common/rt.rs b/library/std/src/sys_common/rt.rs index c70f2ecc04e..02013ecc4ce 100644 --- a/library/std/src/sys_common/rt.rs +++ b/library/std/src/sys_common/rt.rs @@ -1,4 +1,5 @@ #![deny(unsafe_op_in_unsafe_fn)] +#![allow(unused_macros)] use crate::sync::Once; use crate::sys; @@ -38,8 +39,25 @@ pub fn cleanup() { }); } +// Prints to the "panic output", depending on the platform this may be: +// - the standard error output +// - some dedicated platform specific output +// - nothing (so this macro is a no-op) +macro_rules! rtprintpanic { + ($($t:tt)*) => { + if let Some(mut out) = crate::sys::stdio::panic_output() { + let _ = crate::io::Write::write_fmt(&mut out, format_args!($($t)*)); + } + } +} + macro_rules! rtabort { - ($($t:tt)*) => (crate::sys_common::util::abort(format_args!($($t)*))) + ($($t:tt)*) => { + { + rtprintpanic!("fatal runtime error: {}\n", format_args!($($t)*)); + crate::sys::abort_internal(); + } + } } macro_rules! rtassert { @@ -50,7 +68,6 @@ macro_rules! rtassert { }; } -#[allow(unused_macros)] // not used on all platforms macro_rules! rtunwrap { ($ok:ident, $e:expr) => { match $e { diff --git a/library/std/src/sys_common/util.rs b/library/std/src/sys_common/util.rs deleted file mode 100644 index 9f7c3bd8795..00000000000 --- a/library/std/src/sys_common/util.rs +++ /dev/null @@ -1,28 +0,0 @@ -use crate::fmt; -use crate::io::prelude::*; -use crate::sys::stdio::panic_output; -use crate::thread; - -pub fn dumb_print(args: fmt::Arguments<'_>) { - if let Some(mut out) = panic_output() { - let _ = out.write_fmt(args); - } -} - -// Other platforms should use the appropriate platform-specific mechanism for -// aborting the process. If no platform-specific mechanism is available, -// crate::intrinsics::abort() may be used instead. The above implementations cover -// all targets currently supported by libstd. - -pub fn abort(args: fmt::Arguments<'_>) -> ! { - dumb_print(format_args!("fatal runtime error: {}\n", args)); - crate::sys::abort_internal(); -} - -#[allow(dead_code)] // stack overflow detection not enabled on all platforms -pub unsafe fn report_overflow() { - dumb_print(format_args!( - "\nthread '{}' has overflowed its stack\n", - thread::current().name().unwrap_or("<unknown>") - )); -} diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 1f5f26e3e14..e62f4440b36 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -162,6 +162,7 @@ macro_rules! thread_local { macro_rules! __thread_local_inner { // used to generate the `LocalKey` value for const-initialized thread locals (@key $t:ty, const $init:expr) => {{ + #[cfg_attr(not(windows), inline)] // see comments below unsafe fn __getit() -> $crate::option::Option<&'static $t> { const _REQUIRE_UNSTABLE: () = $crate::thread::require_unstable_const_init_thread_local(); @@ -260,6 +261,29 @@ macro_rules! __thread_local_inner { #[inline] fn __init() -> $t { $init } + // When reading this function you might ask "why is this inlined + // everywhere other than Windows?", and that's a very reasonable + // question to ask. The short story is that it segfaults rustc if + // this function is inlined. The longer story is that Windows looks + // to not support `extern` references to thread locals across DLL + // boundaries. This appears to at least not be supported in the ABI + // that LLVM implements. + // + // Because of this we never inline on Windows, but we do inline on + // other platforms (where external references to thread locals + // across DLLs are supported). A better fix for this would be to + // inline this function on Windows, but only for "statically linked" + // components. For example if two separately compiled rlibs end up + // getting linked into a DLL then it's fine to inline this function + // across that boundary. It's only not fine to inline this function + // across a DLL boundary. Unfortunately rustc doesn't currently + // have this sort of logic available in an attribute, and it's not + // clear that rustc is even equipped to answer this (it's more of a + // Cargo question kinda). This means that, unfortunately, Windows + // gets the pessimistic path for now where it's never inlined. + // + // The issue of "should enable on Windows sometimes" is #84933 + #[cfg_attr(not(windows), inline)] unsafe fn __getit() -> $crate::option::Option<&'static $t> { #[cfg(all(target_arch = "wasm32", not(target_feature = "atomics")))] static __KEY: $crate::thread::__StaticLocalKeyInner<$t> = diff --git a/library/std/tests/run-time-detect.rs b/library/std/tests/run-time-detect.rs index 61a04c46722..c7107b5d0a3 100644 --- a/library/std/tests/run-time-detect.rs +++ b/library/std/tests/run-time-detect.rs @@ -27,7 +27,6 @@ fn aarch64_linux() { println!("asimd: {}", is_aarch64_feature_detected!("asimd")); println!("sve: {}", is_aarch64_feature_detected!("sve")); println!("crc: {}", is_aarch64_feature_detected!("crc")); - println!("crypto: {}", is_aarch64_feature_detected!("crypto")); println!("lse: {}", is_aarch64_feature_detected!("lse")); println!("rdm: {}", is_aarch64_feature_detected!("rdm")); println!("rcpc: {}", is_aarch64_feature_detected!("rcpc")); diff --git a/library/stdarch b/library/stdarch -Subproject c14e98417feb406df66e821ccd81e1293b4baa6 +Subproject 37d6e1886369ea0176356286dc7fbd42ee5aa79 diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs index b7791b1b24d..84874a2d225 100644 --- a/library/test/src/cli.rs +++ b/library/test/src/cli.rs @@ -95,8 +95,9 @@ fn optgroups() -> getopts::Options { "Configure formatting of output: pretty = Print verbose output; terse = Display one character per test; - json = Output a json document", - "pretty|terse|json", + json = Output a json document; + junit = Output a JUnit document", + "pretty|terse|json|junit", ) .optflag("", "show-output", "Show captured stdout of successful tests") .optopt( @@ -336,10 +337,15 @@ fn get_format( } OutputFormat::Json } - + Some("junit") => { + if !allow_unstable { + return Err("The \"junit\" format is only accepted on the nightly compiler".into()); + } + OutputFormat::Junit + } Some(v) => { return Err(format!( - "argument for --format must be pretty, terse, or json (was \ + "argument for --format must be pretty, terse, json or junit (was \ {})", v )); diff --git a/library/test/src/console.rs b/library/test/src/console.rs index 1721c3c14f9..9cfc7eaf4bc 100644 --- a/library/test/src/console.rs +++ b/library/test/src/console.rs @@ -10,7 +10,7 @@ use super::{ cli::TestOpts, event::{CompletedTest, TestEvent}, filter_tests, - formatters::{JsonFormatter, OutputFormatter, PrettyFormatter, TerseFormatter}, + formatters::{JsonFormatter, JunitFormatter, OutputFormatter, PrettyFormatter, TerseFormatter}, helpers::{concurrency::get_concurrency, metrics::MetricMap}, options::{Options, OutputFormat}, run_tests, @@ -277,6 +277,7 @@ pub fn run_tests_console(opts: &TestOpts, tests: Vec<TestDescAndFn>) -> io::Resu Box::new(TerseFormatter::new(output, opts.use_color(), max_name_len, is_multithreaded)) } OutputFormat::Json => Box::new(JsonFormatter::new(output)), + OutputFormat::Junit => Box::new(JunitFormatter::new(output)), }; let mut st = ConsoleTestState::new(opts)?; diff --git a/library/test/src/formatters/junit.rs b/library/test/src/formatters/junit.rs new file mode 100644 index 00000000000..ec66fc1219f --- /dev/null +++ b/library/test/src/formatters/junit.rs @@ -0,0 +1,174 @@ +use std::io::{self, prelude::Write}; +use std::time::Duration; + +use super::OutputFormatter; +use crate::{ + console::{ConsoleTestState, OutputLocation}, + test_result::TestResult, + time, + types::{TestDesc, TestType}, +}; + +pub struct JunitFormatter<T> { + out: OutputLocation<T>, + results: Vec<(TestDesc, TestResult, Duration)>, +} + +impl<T: Write> JunitFormatter<T> { + pub fn new(out: OutputLocation<T>) -> Self { + Self { out, results: Vec::new() } + } + + fn write_message(&mut self, s: &str) -> io::Result<()> { + assert!(!s.contains('\n')); + + self.out.write_all(s.as_ref()) + } +} + +impl<T: Write> OutputFormatter for JunitFormatter<T> { + fn write_run_start(&mut self, _test_count: usize) -> io::Result<()> { + // We write xml header on run start + self.write_message(&"<?xml version=\"1.0\" encoding=\"UTF-8\"?>") + } + + fn write_test_start(&mut self, _desc: &TestDesc) -> io::Result<()> { + // We do not output anything on test start. + Ok(()) + } + + fn write_timeout(&mut self, _desc: &TestDesc) -> io::Result<()> { + // We do not output anything on test timeout. + Ok(()) + } + + fn write_result( + &mut self, + desc: &TestDesc, + result: &TestResult, + exec_time: Option<&time::TestExecTime>, + _stdout: &[u8], + _state: &ConsoleTestState, + ) -> io::Result<()> { + // Because the testsuit node holds some of the information as attributes, we can't write it + // until all of the tests has ran. Instead of writting every result as they come in, we add + // them to a Vec and write them all at once when run is complete. + let duration = exec_time.map(|t| t.0.clone()).unwrap_or_default(); + self.results.push((desc.clone(), result.clone(), duration)); + Ok(()) + } + fn write_run_finish(&mut self, state: &ConsoleTestState) -> io::Result<bool> { + self.write_message("<testsuites>")?; + + self.write_message(&*format!( + "<testsuite name=\"test\" package=\"test\" id=\"0\" \ + errors=\"0\" \ + failures=\"{}\" \ + tests=\"{}\" \ + skipped=\"{}\" \ + >", + state.failed, state.total, state.ignored + ))?; + for (desc, result, duration) in std::mem::replace(&mut self.results, Vec::new()) { + let (class_name, test_name) = parse_class_name(&desc); + match result { + TestResult::TrIgnored => { /* no-op */ } + TestResult::TrFailed => { + self.write_message(&*format!( + "<testcase classname=\"{}\" \ + name=\"{}\" time=\"{}\">", + class_name, + test_name, + duration.as_secs() + ))?; + self.write_message("<failure type=\"assert\"/>")?; + self.write_message("</testcase>")?; + } + + TestResult::TrFailedMsg(ref m) => { + self.write_message(&*format!( + "<testcase classname=\"{}\" \ + name=\"{}\" time=\"{}\">", + class_name, + test_name, + duration.as_secs() + ))?; + self.write_message(&*format!("<failure message=\"{}\" type=\"assert\"/>", m))?; + self.write_message("</testcase>")?; + } + + TestResult::TrTimedFail => { + self.write_message(&*format!( + "<testcase classname=\"{}\" \ + name=\"{}\" time=\"{}\">", + class_name, + test_name, + duration.as_secs() + ))?; + self.write_message("<failure type=\"timeout\"/>")?; + self.write_message("</testcase>")?; + } + + TestResult::TrBench(ref b) => { + self.write_message(&*format!( + "<testcase classname=\"benchmark::{}\" \ + name=\"{}\" time=\"{}\" />", + class_name, test_name, b.ns_iter_summ.sum + ))?; + } + + TestResult::TrOk | TestResult::TrAllowedFail => { + self.write_message(&*format!( + "<testcase classname=\"{}\" \ + name=\"{}\" time=\"{}\"/>", + class_name, + test_name, + duration.as_secs() + ))?; + } + } + } + self.write_message("<system-out/>")?; + self.write_message("<system-err/>")?; + self.write_message("</testsuite>")?; + self.write_message("</testsuites>")?; + + Ok(state.failed == 0) + } +} + +fn parse_class_name(desc: &TestDesc) -> (String, String) { + match desc.test_type { + TestType::UnitTest => parse_class_name_unit(desc), + TestType::DocTest => parse_class_name_doc(desc), + TestType::IntegrationTest => parse_class_name_integration(desc), + TestType::Unknown => (String::from("unknown"), String::from(desc.name.as_slice())), + } +} + +fn parse_class_name_unit(desc: &TestDesc) -> (String, String) { + // Module path => classname + // Function name => name + let module_segments: Vec<&str> = desc.name.as_slice().split("::").collect(); + let (class_name, test_name) = match module_segments[..] { + [test] => (String::from("crate"), String::from(test)), + [ref path @ .., test] => (path.join("::"), String::from(test)), + [..] => unreachable!(), + }; + (class_name, test_name) +} + +fn parse_class_name_doc(desc: &TestDesc) -> (String, String) { + // File path => classname + // Line # => test name + let segments: Vec<&str> = desc.name.as_slice().split(" - ").collect(); + let (class_name, test_name) = match segments[..] { + [file, line] => (String::from(file.trim()), String::from(line.trim())), + [..] => unreachable!(), + }; + (class_name, test_name) +} + +fn parse_class_name_integration(desc: &TestDesc) -> (String, String) { + (String::from("integration"), String::from(desc.name.as_slice())) +} diff --git a/library/test/src/formatters/mod.rs b/library/test/src/formatters/mod.rs index 1fb840520a6..2e03581b3af 100644 --- a/library/test/src/formatters/mod.rs +++ b/library/test/src/formatters/mod.rs @@ -8,10 +8,12 @@ use crate::{ }; mod json; +mod junit; mod pretty; mod terse; pub(crate) use self::json::JsonFormatter; +pub(crate) use self::junit::JunitFormatter; pub(crate) use self::pretty::PrettyFormatter; pub(crate) use self::terse::TerseFormatter; diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 9adc099aaa5..bda5ed888d7 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -49,7 +49,7 @@ pub mod test { cli::{parse_opts, TestOpts}, filter_tests, helpers::metrics::{Metric, MetricMap}, - options::{Options, RunIgnored, RunStrategy, ShouldPanic}, + options::{Concurrent, Options, RunIgnored, RunStrategy, ShouldPanic}, run_test, test_main, test_main_static, test_result::{TestResult, TrFailed, TrFailedMsg, TrIgnored, TrOk}, time::{TestExecTime, TestTimeOptions}, diff --git a/library/test/src/options.rs b/library/test/src/options.rs index 8e7bd8de924..baf36b5f1d8 100644 --- a/library/test/src/options.rs +++ b/library/test/src/options.rs @@ -39,6 +39,8 @@ pub enum OutputFormat { Terse, /// JSON output Json, + /// JUnit output + Junit, } /// Whether ignored test should be run or not diff --git a/library/unwind/Cargo.toml b/library/unwind/Cargo.toml index f42ded62585..c76ba7667d4 100644 --- a/library/unwind/Cargo.toml +++ b/library/unwind/Cargo.toml @@ -21,8 +21,15 @@ compiler_builtins = "0.1.0" cfg-if = "0.1.8" [build-dependencies] -cc = "1.0.67" +cc = "1.0.68" [features] + +# Only applies for Linux and Fuchsia targets +# Static link to the in-tree build of llvm libunwind llvm-libunwind = [] + +# Only applies for Linux and Fuchsia targets +# If crt-static is enabled, static link to `libunwind.a` provided by system +# If crt-static is disabled, dynamic link to `libunwind.so` provided by system system-llvm-libunwind = [] diff --git a/library/unwind/build.rs b/library/unwind/build.rs index d8bf152e4d6..0529d24a274 100644 --- a/library/unwind/build.rs +++ b/library/unwind/build.rs @@ -4,7 +4,8 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); let target = env::var("TARGET").expect("TARGET was not set"); - if cfg!(feature = "system-llvm-libunwind") { + if cfg!(target_os = "linux") && cfg!(feature = "system-llvm-libunwind") { + // linking for Linux is handled in lib.rs return; } @@ -19,6 +20,20 @@ fn main() { // linking for Linux is handled in lib.rs if target.contains("musl") { llvm_libunwind::compile(); + } else if target.contains("android") { + let build = cc::Build::new(); + + // Since ndk r23 beta 3 `libgcc` was replaced with `libunwind` thus + // check if we have `libunwind` available and if so use it. Otherwise + // fall back to `libgcc` to support older ndk versions. + 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"); + } } } else if target.contains("freebsd") { println!("cargo:rustc-link-lib=gcc_s"); @@ -57,101 +72,102 @@ mod llvm_libunwind { pub fn compile() { let target = env::var("TARGET").expect("TARGET was not set"); let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap(); - let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap(); - let target_endian_little = env::var("CARGO_CFG_TARGET_ENDIAN").unwrap() != "big"; - let cfg = &mut cc::Build::new(); - - cfg.cpp(true); - cfg.cpp_set_stdlib(None); - cfg.warnings(false); + let mut cc_cfg = cc::Build::new(); + let mut cpp_cfg = cc::Build::new(); + let root = Path::new("../../src/llvm-project/libunwind"); - // libunwind expects a __LITTLE_ENDIAN__ macro to be set for LE archs, cf. #65765 - if target_endian_little { - cfg.define("__LITTLE_ENDIAN__", Some("1")); + cpp_cfg.cpp(true); + cpp_cfg.cpp_set_stdlib(None); + cpp_cfg.flag("-nostdinc++"); + cpp_cfg.flag("-fno-exceptions"); + cpp_cfg.flag("-fno-rtti"); + cpp_cfg.flag_if_supported("-fvisibility-global-new-delete-hidden"); + + // Don't set this for clang + // By default, Clang builds C code in GNU C17 mode. + // By default, Clang builds C++ code according to the C++98 standard, + // with many C++11 features accepted as extensions. + if cpp_cfg.get_compiler().is_like_gnu() { + cpp_cfg.flag("-std=c++11"); + cc_cfg.flag("-std=c99"); } - if target_env == "msvc" { - // Don't pull in extra libraries on MSVC - cfg.flag("/Zl"); - cfg.flag("/EHsc"); - cfg.define("_CRT_SECURE_NO_WARNINGS", None); - cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None); - } else if target.contains("x86_64-fortanix-unknown-sgx") { - cfg.cpp(false); - - cfg.static_flag(true); - cfg.opt_level(3); - - cfg.flag("-nostdinc++"); - cfg.flag("-fno-exceptions"); - cfg.flag("-fno-rtti"); - cfg.flag("-fstrict-aliasing"); - cfg.flag("-funwind-tables"); - cfg.flag("-fvisibility=hidden"); - cfg.flag("-fno-stack-protector"); - cfg.flag("-ffreestanding"); - cfg.flag("-fexceptions"); - - // easiest way to undefine since no API available in cc::Build to undefine - cfg.flag("-U_FORTIFY_SOURCE"); - cfg.define("_FORTIFY_SOURCE", "0"); - - cfg.flag_if_supported("-fvisibility-global-new-delete-hidden"); + if target.contains("x86_64-fortanix-unknown-sgx") || target_env == "musl" { + // use the same GCC C compiler command to compile C++ code so we do not need to setup the + // C++ compiler env variables on the builders. + // Don't set this for clang++, as clang++ is able to compile this without libc++. + if cpp_cfg.get_compiler().is_like_gnu() { + cpp_cfg.cpp(false); + } + } - cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None); - cfg.define("RUST_SGX", "1"); - cfg.define("__NO_STRING_INLINES", None); - cfg.define("__NO_MATH_INLINES", None); - cfg.define("_LIBUNWIND_IS_BAREMETAL", None); - cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None); - cfg.define("NDEBUG", None); - } else { - cfg.flag("-std=c99"); - cfg.flag("-std=c++11"); - cfg.flag("-nostdinc++"); - cfg.flag("-fno-exceptions"); - cfg.flag("-fno-rtti"); + for cfg in [&mut cc_cfg, &mut cpp_cfg].iter_mut() { + cfg.warnings(false); cfg.flag("-fstrict-aliasing"); cfg.flag("-funwind-tables"); cfg.flag("-fvisibility=hidden"); - cfg.flag_if_supported("-fvisibility-global-new-delete-hidden"); cfg.define("_LIBUNWIND_DISABLE_VISIBILITY_ANNOTATIONS", None); + cfg.include(root.join("include")); + cfg.cargo_metadata(false); + + if target.contains("x86_64-fortanix-unknown-sgx") { + cfg.static_flag(true); + cfg.opt_level(3); + cfg.flag("-fno-stack-protector"); + cfg.flag("-ffreestanding"); + cfg.flag("-fexceptions"); + + // easiest way to undefine since no API available in cc::Build to undefine + cfg.flag("-U_FORTIFY_SOURCE"); + cfg.define("_FORTIFY_SOURCE", "0"); + cfg.define("RUST_SGX", "1"); + cfg.define("__NO_STRING_INLINES", None); + cfg.define("__NO_MATH_INLINES", None); + cfg.define("_LIBUNWIND_IS_BAREMETAL", None); + cfg.define("__LIBUNWIND_IS_NATIVE_ONLY", None); + cfg.define("NDEBUG", None); + } } - let mut unwind_sources = vec![ - "Unwind-EHABI.cpp", - "Unwind-seh.cpp", + let mut c_sources = vec![ "Unwind-sjlj.c", "UnwindLevel1-gcc-ext.c", "UnwindLevel1.c", "UnwindRegistersRestore.S", "UnwindRegistersSave.S", - "libunwind.cpp", ]; - if target_vendor == "apple" { - unwind_sources.push("Unwind_AppleExtras.cpp"); - } + let cpp_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"]; + let cpp_len = cpp_sources.len(); if target.contains("x86_64-fortanix-unknown-sgx") { - unwind_sources.push("UnwindRustSgx.c"); + c_sources.push("UnwindRustSgx.c"); } - let root = Path::new("../../src/llvm-project/libunwind"); - cfg.include(root.join("include")); - for src in unwind_sources { - cfg.file(root.join("src").join(src)); + for src in c_sources { + cc_cfg.file(root.join("src").join(src).canonicalize().unwrap()); } - if target_env == "musl" { - // use the same C compiler command to compile C++ code so we do not need to setup the - // C++ compiler env variables on the builders - cfg.cpp(false); - // linking for musl is handled in lib.rs - cfg.cargo_metadata(false); - println!("cargo:rustc-link-search=native={}", env::var("OUT_DIR").unwrap()); + for src in cpp_sources { + cpp_cfg.file(root.join("src").join(src).canonicalize().unwrap()); } - cfg.compile("unwind"); + let out_dir = env::var("OUT_DIR").unwrap(); + println!("cargo:rustc-link-search=native={}", &out_dir); + + cpp_cfg.compile("unwind-cpp"); + + let mut count = 0; + for entry in std::fs::read_dir(&out_dir).unwrap() { + let obj = entry.unwrap().path().canonicalize().unwrap(); + if let Some(ext) = obj.extension() { + if ext == "o" { + cc_cfg.object(&obj); + count += 1; + } + } + } + assert_eq!(cpp_len, count, "Can't get object files from {:?}", &out_dir); + cc_cfg.compile("unwind"); } } diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index be5e56c71e3..eaeec72fbb5 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -37,9 +37,22 @@ cfg_if::cfg_if! { } #[cfg(target_env = "musl")] -#[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))] -#[link(name = "gcc_s", cfg(not(target_feature = "crt-static")))] -extern "C" {} +cfg_if::cfg_if! { + if #[cfg(all(feature = "llvm-libunwind", feature = "system-llvm-libunwind"))] { + compile_error!("`llvm-libunwind` and `system-llvm-libunwind` cannot be enabled at the same time"); + } else if #[cfg(feature = "llvm-libunwind")] { + #[link(name = "unwind", kind = "static")] + extern "C" {} + } else if #[cfg(feature = "system-llvm-libunwind")] { + #[link(name = "unwind", kind = "static-nobundle", cfg(target_feature = "crt-static"))] + #[link(name = "unwind", cfg(not(target_feature = "crt-static")))] + extern "C" {} + } else { + #[link(name = "unwind", kind = "static", cfg(target_feature = "crt-static"))] + #[link(name = "gcc_s", 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 @@ -68,5 +81,5 @@ extern "C" {} extern "C" {} #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] -#[link(name = "unwind", kind = "static-nobundle")] +#[link(name = "unwind", kind = "static")] extern "C" {} diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index a74df97a5c7..8445d811e0f 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -40,7 +40,7 @@ cmake = "0.1.38" filetime = "0.2" num_cpus = "1.0" getopts = "0.2.19" -cc = "1.0.67" +cc = "1.0.68" libc = "0.2" serde = { version = "1.0.8", features = ["derive"] } serde_json = "1.0.2" diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index d462dc4d116..4b98abfb308 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -305,7 +305,7 @@ fn format_rusage_data(_child: Child) -> Option<String> { }; // Mac OS X reports the maxrss in bytes, not kb. let divisor = if env::consts::OS == "macos" { 1024 } else { 1 }; - let maxrss = rusage.ru_maxrss + (divisor - 1) / divisor; + let maxrss = (rusage.ru_maxrss + (divisor - 1)) / divisor; let mut init_str = format!( "user: {USER_SEC}.{USER_USEC:03} \ diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index f39e89a9d01..da298f7edb9 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -369,7 +369,8 @@ impl<'a> Builder<'a> { tool::Rustfmt, tool::Miri, tool::CargoMiri, - native::Lld + native::Lld, + native::CrtBeginEnd ), Kind::Check | Kind::Clippy { .. } | Kind::Fix | Kind::Format => describe!( check::Std, @@ -708,7 +709,15 @@ impl<'a> Builder<'a> { return; } - add_dylib_path(vec![self.rustc_libdir(compiler)], cmd); + let mut dylib_dirs = vec![self.rustc_libdir(compiler)]; + + // Ensure that the downloaded LLVM libraries can be found. + if self.config.llvm_from_ci { + let ci_llvm_lib = self.out.join(&*compiler.host.triple).join("ci-llvm").join("lib"); + dylib_dirs.push(ci_llvm_lib); + } + + add_dylib_path(dylib_dirs, cmd); } /// Gets a path to the compiler specified. diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 2676b3bf8e0..e5258d08956 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -199,8 +199,9 @@ fn copy_self_contained_objects( DependencyType::TargetSelfContained, ); } + let crt_path = builder.ensure(native::CrtBeginEnd { target }); for &obj in &["crtbegin.o", "crtbeginS.o", "crtend.o", "crtendS.o"] { - let src = compiler_file(builder, builder.cc(target), target, obj); + let src = crt_path.join(obj); let target = libdir_self_contained.join(obj); builder.copy(&src, &target); target_deps.push((target, DependencyType::TargetSelfContained)); diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index f9972ac7b9d..d2fabf9967f 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -434,6 +434,7 @@ impl Step for Std { cargo .arg("-p") .arg(package) + .arg("-Zskip-rustdoc-fingerprint") .arg("--") .arg("--markdown-css") .arg("rust.css") @@ -564,6 +565,7 @@ impl Step for Rustc { cargo.rustdocflag("-Znormalize-docs"); cargo.rustdocflag("--show-type-layout"); compile::rustc_cargo(builder, &mut cargo, target); + cargo.arg("-Zskip-rustdoc-fingerprint"); // Only include compiler crates, no dependencies of those, such as `libc`. cargo.arg("--no-deps"); @@ -655,6 +657,7 @@ impl Step for Rustdoc { &[], ); + cargo.arg("-Zskip-rustdoc-fingerprint"); // Only include compiler crates, no dependencies of those, such as `libc`. cargo.arg("--no-deps"); cargo.arg("-p").arg("rustdoc"); diff --git a/src/bootstrap/mk/Makefile.in b/src/bootstrap/mk/Makefile.in index 47cf1172d36..fd39944e176 100644 --- a/src/bootstrap/mk/Makefile.in +++ b/src/bootstrap/mk/Makefile.in @@ -45,10 +45,6 @@ check-aux: src/tools/cargo \ src/tools/cargotest \ $(BOOTSTRAP_ARGS) -check-aux-and-gui: check-aux - $(Q)$(BOOTSTRAP) test --stage 2 \ - src/test/rustdoc-gui \ - $(BOOTSTRAP_ARGS) check-bootstrap: $(Q)$(CFG_PYTHON) $(CFG_SRC_DIR)src/bootstrap/bootstrap_test.py dist: diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index bde0a96f030..4f33a13c253 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -181,7 +181,7 @@ impl Step for Llvm { .define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native); - if target != "aarch64-apple-darwin" { + if target != "aarch64-apple-darwin" && !target.contains("windows") { cfg.define("LLVM_ENABLE_ZLIB", "ON"); } else { cfg.define("LLVM_ENABLE_ZLIB", "OFF"); @@ -858,3 +858,69 @@ impl HashStamp { fs::write(&self.path, self.hash.as_deref().unwrap_or(b"")) } } + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct CrtBeginEnd { + pub target: TargetSelection, +} + +impl Step for CrtBeginEnd { + type Output = PathBuf; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/llvm-project/compiler-rt/lib/crt") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(CrtBeginEnd { target: run.target }); + } + + /// Build crtbegin.o/crtend.o for musl target. + fn run(self, builder: &Builder<'_>) -> Self::Output { + let out_dir = builder.native_dir(self.target).join("crt"); + + if builder.config.dry_run { + return out_dir; + } + + let crtbegin_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtbegin.c"); + let crtend_src = builder.src.join("src/llvm-project/compiler-rt/lib/crt/crtend.c"); + if up_to_date(&crtbegin_src, &out_dir.join("crtbegin.o")) + && up_to_date(&crtend_src, &out_dir.join("crtendS.o")) + { + return out_dir; + } + + builder.info("Building crtbegin.o and crtend.o"); + t!(fs::create_dir_all(&out_dir)); + + let mut cfg = cc::Build::new(); + + if let Some(ar) = builder.ar(self.target) { + cfg.archiver(ar); + } + cfg.compiler(builder.cc(self.target)); + cfg.cargo_metadata(false) + .out_dir(&out_dir) + .target(&self.target.triple) + .host(&builder.config.build.triple) + .warnings(false) + .debug(false) + .opt_level(3) + .file(crtbegin_src) + .file(crtend_src); + + // Those flags are defined in src/llvm-project/compiler-rt/lib/crt/CMakeLists.txt + // Currently only consumer of those objects is musl, which use .init_array/.fini_array + // instead of .ctors/.dtors + cfg.flag("-std=c11") + .define("CRT_HAS_INITFINI_ARRAY", None) + .define("EH_USE_FRAME_REGISTRY", None); + + cfg.compile("crt"); + + t!(fs::copy(out_dir.join("crtbegin.o"), out_dir.join("crtbeginS.o"))); + t!(fs::copy(out_dir.join("crtend.o"), out_dir.join("crtendS.o"))); + out_dir + } +} diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index ed0cbdf97b0..a28762ac485 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -93,7 +93,8 @@ pub fn check(build: &mut Build) { .unwrap_or(true) }) .any(|build_llvm_ourselves| build_llvm_ourselves); - if building_llvm || build.config.any_sanitizers_enabled() { + let need_cmake = building_llvm || build.config.any_sanitizers_enabled(); + if need_cmake { cmd_finder.must_have("cmake"); } @@ -204,7 +205,7 @@ pub fn check(build: &mut Build) { } } - if target.contains("msvc") { + if need_cmake && target.contains("msvc") { // There are three builds of cmake on windows: MSVC, MinGW, and // Cygwin. The Cygwin build does not have generators for Visual // Studio, so detect that here and error. diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 98f753b25f0..7bd29c61b0c 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -449,6 +449,7 @@ impl Step for Miri { SourceType::Submodule, &[], ); + cargo.add_rustc_lib_path(builder, compiler); cargo.arg("--").arg("miri").arg("setup"); // Tell `cargo miri setup` where to find the sources. @@ -500,6 +501,7 @@ impl Step for Miri { SourceType::Submodule, &[], ); + cargo.add_rustc_lib_path(builder, compiler); // miri tests need to know about the stage sysroot cargo.env("MIRI_SYSROOT", miri_sysroot); @@ -508,8 +510,6 @@ impl Step for Miri { cargo.arg("--").args(builder.config.cmd.test_args()); - cargo.add_rustc_lib_path(builder, compiler); - let mut cargo = Command::from(cargo); if !try_run(builder, &mut cargo) { return; @@ -774,6 +774,24 @@ impl Step for RustdocJSNotStd { } } +fn check_if_browser_ui_test_is_installed_global(npm: &Path, global: bool) -> bool { + let mut command = Command::new(&npm); + command.arg("list").arg("--depth=0"); + if global { + command.arg("--global"); + } + let lines = command + .output() + .map(|output| String::from_utf8_lossy(&output.stdout).into_owned()) + .unwrap_or(String::new()); + lines.contains(&" browser-ui-test@") +} + +fn check_if_browser_ui_test_is_installed(npm: &Path) -> bool { + check_if_browser_ui_test_is_installed_global(npm, false) + || check_if_browser_ui_test_is_installed_global(npm, true) +} + #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocGUI { pub target: TargetSelection, @@ -786,7 +804,17 @@ impl Step for RustdocGUI { const ONLY_HOSTS: bool = true; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/test/rustdoc-gui") + let builder = run.builder; + let run = run.path("src/test/rustdoc-gui"); + run.default_condition( + builder.config.nodejs.is_some() + && builder + .config + .npm + .as_ref() + .map(|p| check_if_browser_ui_test_is_installed(p)) + .unwrap_or(false), + ) } fn make_run(run: RunConfig<'_>) { @@ -795,58 +823,54 @@ impl Step for RustdocGUI { } fn run(self, builder: &Builder<'_>) { - if let (Some(nodejs), Some(npm)) = (&builder.config.nodejs, &builder.config.npm) { - builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); - - // The goal here is to check if the necessary packages are installed, and if not, we - // display a warning and move on. - let mut command = Command::new(&npm); - command.arg("list").arg("--depth=0"); - let lines = command - .output() - .map(|output| String::from_utf8_lossy(&output.stdout).to_string()) - .unwrap_or(String::new()); - if !lines.contains(&" browser-ui-test@") { - println!( - "warning: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \ - dependency is missing", - ); - println!( - "If you want to install the `{0}` dependency, run `npm install {0}`", - "browser-ui-test", - ); - return; - } + let nodejs = builder.config.nodejs.as_ref().expect("nodejs isn't available"); + let npm = builder.config.npm.as_ref().expect("npm isn't available"); - let out_dir = builder.test_out(self.target).join("rustdoc-gui"); + builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); - // We remove existing folder to be sure there won't be artifacts remaining. - let _ = fs::remove_dir_all(&out_dir); + // The goal here is to check if the necessary packages are installed, and if not, we + // panic. + if !check_if_browser_ui_test_is_installed(&npm) { + eprintln!( + "error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` \ + dependency is missing", + ); + eprintln!( + "If you want to install the `{0}` dependency, run `npm install {0}`", + "browser-ui-test", + ); + panic!("Cannot run rustdoc-gui tests"); + } - // We generate docs for the libraries present in the rustdoc-gui's src folder. - let libs_dir = builder.build.src.join("src/test/rustdoc-gui/src"); - for entry in libs_dir.read_dir().expect("read_dir call failed") { - let entry = entry.expect("invalid entry"); - let path = entry.path(); - if path.extension().map(|e| e == "rs").unwrap_or(false) { - let mut command = builder.rustdoc_cmd(self.compiler); - command.arg(path).arg("-o").arg(&out_dir); - builder.run(&mut command); - } - } + let out_dir = builder.test_out(self.target).join("rustdoc-gui"); - // We now run GUI tests. - let mut command = Command::new(&nodejs); - command - .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js")) - .arg("--doc-folder") - .arg(out_dir) - .arg("--tests-folder") - .arg(builder.build.src.join("src/test/rustdoc-gui")); - builder.run(&mut command); - } else { - builder.info("No nodejs found, skipping \"src/test/rustdoc-gui\" tests"); + // We remove existing folder to be sure there won't be artifacts remaining. + let _ = fs::remove_dir_all(&out_dir); + + let mut nb_generated = 0; + // We generate docs for the libraries present in the rustdoc-gui's src folder. + let libs_dir = builder.build.src.join("src/test/rustdoc-gui/src"); + for entry in libs_dir.read_dir().expect("read_dir call failed") { + let entry = entry.expect("invalid entry"); + let path = entry.path(); + if path.extension().map(|e| e == "rs").unwrap_or(false) { + let mut command = builder.rustdoc_cmd(self.compiler); + command.arg(path).arg("-o").arg(&out_dir); + builder.run(&mut command); + nb_generated += 1; + } } + assert!(nb_generated > 0, "no documentation was generated..."); + + // We now run GUI tests. + let mut command = Command::new(&nodejs); + command + .arg(builder.build.src.join("src/tools/rustdoc-gui/tester.js")) + .arg("--doc-folder") + .arg(out_dir) + .arg("--tests-folder") + .arg(builder.build.src.join("src/test/rustdoc-gui")); + builder.run(&mut command); } } diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index 12571c1b97d..64e4be6863a 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -52,7 +52,10 @@ impl Step for ToolBuild { let is_optional_tool = self.is_optional_tool; match self.mode { - Mode::ToolRustc => builder.ensure(compile::Rustc { compiler, target }), + Mode::ToolRustc => { + builder.ensure(compile::Std { compiler, target: compiler.host }); + builder.ensure(compile::Rustc { compiler, target }); + } Mode::ToolStd => builder.ensure(compile::Std { compiler, target }), Mode::ToolBootstrap => {} // uses downloaded stage0 compiler libs _ => panic!("unexpected Mode for tool build"), @@ -214,9 +217,8 @@ impl Step for ToolBuild { if tool == "tidy" { tool = "rust-tidy"; } - let cargo_out = - builder.cargo_out(compiler, self.mode, target).join(exe(tool, compiler.host)); - let bin = builder.tools_dir(compiler).join(exe(tool, compiler.host)); + let cargo_out = builder.cargo_out(compiler, self.mode, target).join(exe(tool, target)); + let bin = builder.tools_dir(compiler).join(exe(tool, target)); builder.copy(&cargo_out, &bin); Some(bin) } @@ -593,7 +595,14 @@ impl Step for Cargo { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.path("src/tools/cargo").default_condition(builder.config.extended) + run.path("src/tools/cargo").default_condition( + builder.config.extended + && builder.config.tools.as_ref().map_or( + true, + // If `tools` is set, search list for this tool. + |tools| tools.iter().any(|tool| tool == "cargo"), + ), + ) } fn make_run(run: RunConfig<'_>) { diff --git a/src/bootstrap/util.rs b/src/bootstrap/util.rs index b4421a82714..4c1cd758f0d 100644 --- a/src/bootstrap/util.rs +++ b/src/bootstrap/util.rs @@ -45,6 +45,7 @@ pub fn libdir(target: TargetSelection) -> &'static str { } /// Adds a list of lookup paths to `cmd`'s dynamic library lookup path. +/// If The dylib_path_par is already set for this cmd, the old value will be overwritten! pub fn add_dylib_path(path: Vec<PathBuf>, cmd: &mut Command) { let mut list = dylib_path(); for path in path { diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile index 1f8f9fc518a..cd0f01faa1b 100644 --- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile @@ -144,7 +144,11 @@ ENV TARGETS=$TARGETS,armv7a-none-eabi # riscv targets currently do not need a C compiler, as compiler_builtins # doesn't currently have it enabled, and the riscv gcc compiler is not # installed. -ENV CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ +ENV CFLAGS_armv5te_unknown_linux_musleabi="-march=armv5te -marm -mfloat-abi=soft" \ + CFLAGS_arm_unknown_linux_musleabi="-march=armv6 -marm" \ + CFLAGS_arm_unknown_linux_musleabihf="-march=armv6 -marm -mfpu=vfp" \ + CFLAGS_armv7_unknown_linux_musleabihf="-march=armv7-a" \ + CC_mipsel_unknown_linux_musl=mipsel-openwrt-linux-gcc \ CC_mips_unknown_linux_musl=mips-openwrt-linux-gcc \ CC_mips64el_unknown_linux_muslabi64=mips64el-linux-gnuabi64-gcc \ CC_mips64_unknown_linux_muslabi64=mips64-linux-gnuabi64-gcc \ diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index de3a99f34fc..b7f181adf2a 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -42,6 +42,9 @@ ENV \ AR_x86_64_pc_solaris=x86_64-pc-solaris2.10-ar \ CC_x86_64_pc_solaris=x86_64-pc-solaris2.10-gcc \ CXX_x86_64_pc_solaris=x86_64-pc-solaris2.10-g++ \ + AR_x86_64_sun_solaris=x86_64-sun-solaris2.10-ar \ + CC_x86_64_sun_solaris=x86_64-sun-solaris2.10-gcc \ + CXX_x86_64_sun_solaris=x86_64-sun-solaris2.10-g++ \ CC_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-gcc-8 \ CXX_armv7_unknown_linux_gnueabi=arm-linux-gnueabi-g++-8 \ AR_x86_64_fortanix_unknown_sgx=ar \ @@ -68,8 +71,10 @@ COPY host-x86_64/dist-various-2/shared.sh /tmp/ COPY host-x86_64/dist-various-2/build-fuchsia-toolchain.sh /tmp/ RUN /tmp/build-fuchsia-toolchain.sh COPY host-x86_64/dist-various-2/build-solaris-toolchain.sh /tmp/ -RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386 -RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc +RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386 pc +# Build deprecated target 'x86_64-sun-solaris2.10' until removed +RUN /tmp/build-solaris-toolchain.sh x86_64 amd64 solaris-i386 sun +RUN /tmp/build-solaris-toolchain.sh sparcv9 sparcv9 solaris-sparc sun COPY host-x86_64/dist-various-2/build-x86_64-fortanix-unknown-sgx-toolchain.sh /tmp/ RUN /tmp/build-x86_64-fortanix-unknown-sgx-toolchain.sh @@ -99,6 +104,7 @@ ENV TARGETS=$TARGETS,wasm32-unknown-unknown ENV TARGETS=$TARGETS,wasm32-wasi ENV TARGETS=$TARGETS,sparcv9-sun-solaris ENV TARGETS=$TARGETS,x86_64-pc-solaris +ENV TARGETS=$TARGETS,x86_64-sun-solaris ENV TARGETS=$TARGETS,x86_64-unknown-linux-gnux32 ENV TARGETS=$TARGETS,x86_64-fortanix-unknown-sgx ENV TARGETS=$TARGETS,nvptx64-nvidia-cuda diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh index ee76fafb1f9..4cbc2ccfe38 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-solaris-toolchain.sh @@ -6,21 +6,11 @@ source shared.sh ARCH=$1 LIB_ARCH=$2 APT_ARCH=$3 +MANUFACTURER=$4 BINUTILS=2.28.1 GCC=6.5.0 -# Choose correct target based on the $ARCH -case "$ARCH" in -x86_64) - TARGET=x86_64-pc-solaris2.10 - ;; -sparcv9) - TARGET=sparcv9-sun-solaris2.10 - ;; -*) - printf 'ERROR: unknown architecture: %s\n' "$ARCH" - exit 1 -esac +TARGET=${ARCH}-${MANUFACTURER}-solaris2.10 # First up, build binutils mkdir binutils diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index fd6dc563a0e..66afe84be4a 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -22,6 +22,7 @@ ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" # Install es-check # Pin its version to prevent unrelated CI failures due to future es-check versions. RUN npm install es-check@5.2.3 -g +RUN npm install eslint@7.20.0 -g COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -37,4 +38,5 @@ ENV SCRIPT python3 ../x.py --stage 2 test src/tools/expand-yaml-anchors && \ python3 ../x.py doc --stage 0 library/test && \ /scripts/validate-toolstate.sh && \ # Runs checks to ensure that there are no ES5 issues in our JS code. - es-check es5 ../src/librustdoc/html/static/*.js + es-check es5 ../src/librustdoc/html/static/*.js && \ + eslint ../src/librustdoc/html/static/*.js 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 00ad7b0a710..7f1a5820e22 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 @@ -17,27 +17,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libgl1-mesa-dev \ llvm-dev \ libfreetype6-dev \ - libexpat1-dev \ - libexpat1-dev \ - gnupg \ - apt-utils \ - wget \ - fonts-ipafont-gothic \ - fonts-wqy-zenhei \ - fonts-thai-tlwg \ - fonts-kacst \ - fonts-freefont-ttf \ - libxss1 \ - libxtst6 - -RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ -ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" - -# Install required dependencies from browser-UI-test framework -# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries -# to create a new folder. For reference: -# https://github.com/puppeteer/puppeteer/issues/375 -RUN npm install browser-ui-test -g --unsafe-perm=true + libexpat1-dev COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -46,4 +26,4 @@ COPY scripts/cmake.sh /scripts/ RUN /scripts/cmake.sh ENV RUST_CONFIGURE_ARGS --build=x86_64-unknown-linux-gnu -ENV RUST_CHECK_TARGET check-aux-and-gui +ENV RUST_CHECK_TARGET check-aux 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 d4838c0d6f8..605d988dad7 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 @@ -12,8 +12,48 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ cmake \ libssl-dev \ sudo \ - xz-utils \ - pkg-config + xz-utils + +# Install dependencies for chromium browser +RUN apt-get install -y \ + gconf-service \ + libasound2 \ + libatk1.0-0 \ + libatk-bridge2.0-0 \ + libc6 \ + libcairo2 \ + libcups2 \ + libdbus-1-3 \ + libexpat1 \ + libfontconfig1 \ + libgcc1 \ + libgconf-2-4 \ + libgdk-pixbuf2.0-0 \ + libglib2.0-0 \ + libgtk-3-0 \ + libnspr4 \ + libpango-1.0-0 \ + libpangocairo-1.0-0 \ + libstdc++6 \ + libx11-6 \ + libx11-xcb1 \ + libxcb1 \ + libxcomposite1 \ + libxcursor1 \ + libxdamage1 \ + libxext6 \ + libxfixes3 \ + libxi6 \ + libxrandr2 \ + libxrender1 \ + libxss1 \ + libxtst6 \ + fonts-liberation \ + libappindicator1 \ + libnss3 \ + lsb-release \ + xdg-utils \ + wget COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh @@ -23,7 +63,19 @@ RUN /scripts/cmake.sh COPY host-x86_64/x86_64-gnu-tools/checktools.sh /tmp/ +RUN curl -sL https://nodejs.org/dist/v14.4.0/node-v14.4.0-linux-x64.tar.xz | tar -xJ +ENV PATH="/node-v14.4.0-linux-x64/bin:${PATH}" + +# For now, we need to use `--unsafe-perm=true` to go around an issue when npm tries +# to create a new folder. For reference: +# https://github.com/puppeteer/puppeteer/issues/375 +# +# We also specify the version in case we need to update it to go around cache limitations. +RUN npm install -g browser-ui-test@0.2.12 --unsafe-perm=true + ENV RUST_CONFIGURE_ARGS \ --build=x86_64-unknown-linux-gnu \ --save-toolstates=/tmp/toolstate/toolstates.json -ENV SCRIPT /tmp/checktools.sh ../x.py + +ENV SCRIPT /tmp/checktools.sh ../x.py && \ + NODE_PATH=`npm root -g` python3 ../x.py test src/test/rustdoc-gui --stage 2 diff --git a/src/ci/scripts/should-skip-this.sh b/src/ci/scripts/should-skip-this.sh index 631a7b247d5..fa738fe70c8 100755 --- a/src/ci/scripts/should-skip-this.sh +++ b/src/ci/scripts/should-skip-this.sh @@ -26,6 +26,12 @@ elif ! git diff --quiet "$BASE_COMMIT" -- src/tools/clippy src/tools/rustfmt; th # There is not an easy blanket search for subtrees. For now, manually list # the subtrees. echo "Executing the job since clippy or rustfmt subtree was updated" +elif ! (git diff --quiet "$BASE_COMMIT" -- \ + src/test/rustdoc-gui \ + src/librustdoc \ + src/tools/rustdoc-gui); then + # There was a change in either rustdoc or in its GUI tests. + echo "Executing the job since rustdoc was updated" else echo "Not executing this job since no submodules nor subtrees were updated" ciCommandSetEnv SKIP_JOB 1 diff --git a/src/doc/edition-guide b/src/doc/edition-guide -Subproject 1da3c411f17adb1ba5de1683bb6acee83362b54 +Subproject 302a115e8f71876dfc884aebb0ca5ccb02b8a96 diff --git a/src/doc/embedded-book b/src/doc/embedded-book -Subproject 569c3391f5c0cc43433bc77831d17f8ff4d7660 +Subproject 7349d173fa28a0bb834cf0264a05286620ef092 diff --git a/src/doc/reference b/src/doc/reference -Subproject 5aa457bf1b54bd2cd5d4cf49797f29299bdf89a +Subproject 9c68af3ce6ccca2395e1868addef26a0542e9dd diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example -Subproject 5f8c6da200ada77760a2fe1096938ef58151c9a +Subproject 805e016c5792ad2adabb66e348233067d5ea9f1 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide -Subproject 1e6c7fbda4c45e85adf63ff3f82fa9c870b1447 +Subproject 50de7f0682adc5d95ce858fe6318d19b4b95155 diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index b269aab9814..bc1873b6836 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -13,6 +13,7 @@ - [JSON Output](json.md) - [Tests](tests/index.md) - [Platform Support](platform-support.md) + - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md) - [Target Tier Policy](target-tier-policy.md) - [Targets](targets/index.md) - [Built-in Targets](targets/built-in.md) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index f9a7599c497..321d3c5c44e 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -144,7 +144,7 @@ target | std | notes `mips64-unknown-linux-muslabi64` | ✓ | MIPS64 Linux, n64 ABI, MUSL `mips64el-unknown-linux-muslabi64` | ✓ | MIPS64 (LE) Linux, n64 ABI, MUSL `mipsel-unknown-linux-musl` | ✓ | MIPS (LE) Linux with MUSL -`nvptx64-nvidia-cuda` | ✓ | --emit=asm generates PTX code that [runs on NVIDIA GPUs] +`nvptx64-nvidia-cuda` | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs] `riscv32i-unknown-none-elf` | * | Bare RISC-V (RV32I ISA) `riscv32imac-unknown-none-elf` | * | Bare RISC-V (RV32IMAC ISA) `riscv32imc-unknown-none-elf` | * | Bare RISC-V (RV32IMC ISA) @@ -196,7 +196,7 @@ host tools. target | std | host | notes -------|:---:|:----:|------- `aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64 -`aarch64-apple-ios-sim` | ? | | Apple iOS Simulator on ARM64 +[`aarch64-apple-ios-sim`](platform-support/aarch64-apple-ios-sim.md) | ✓ | | Apple iOS Simulator on ARM64 `aarch64-apple-tvos` | * | | ARM64 tvOS `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ? | | diff --git a/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md b/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md new file mode 100644 index 00000000000..9aa5db26f91 --- /dev/null +++ b/src/doc/rustc/src/platform-support/aarch64-apple-ios-sim.md @@ -0,0 +1,56 @@ +# aarch64-apple-ios-sim + +**Tier: 3** + +Apple iOS Simulator on ARM64. + +## Designated Developers + +* [@badboy](https://github.com/badboy) +* [@deg4uss3r](https://github.com/deg4uss3r) + +## Requirements + +This target is cross-compiled. +To build this target Xcode 12 or higher on macOS is required. + +## Building + +The target can be built by enabling it for a `rustc` build: + +```toml +[build] +build-stage = 1 +target = ["aarch64-apple-ios-sim"] +``` + +## Cross-compilation + +This target can be cross-compiled from `x86_64` or `aarch64` macOS hosts. + +Other hosts are not supported for cross-compilation, but might work when also providing the required Xcode SDK. + +## Testing + +Currently there is no support to run the rustc test suite for this target. + + +## Building Rust programs + +*Note: Building for this target requires the corresponding iOS SDK, as provided by Xcode 12+.* + +If `rustc` has support for that target and the library artifacts are available, +then Rust programs can be built for that target: + +```text +rustc --target aarch64-apple-ios-sim your-code.rs +``` + +On Rust Nightly it is possible to build without the target artifacts available: + +```text +cargo build -Z build-std --target aarch64-apple-ios-sim +``` + +There is no easy way to run simple programs in the iOS simulator. +Static library builds can be embedded into iOS applications. diff --git a/src/doc/rustdoc/README.md b/src/doc/rustdoc/README.md new file mode 100644 index 00000000000..7d97d5e4ab5 --- /dev/null +++ b/src/doc/rustdoc/README.md @@ -0,0 +1,5 @@ +# Rustdoc + +This is documentation for rustdoc itself, written in mdbook format. +To build the book, use `x.py doc src/doc/rustdoc`. +To run doctests, use `x.py test src/doc/rustdoc`. diff --git a/src/doc/rustdoc/src/how-to-write-documentation.md b/src/doc/rustdoc/src/how-to-write-documentation.md index 688be7aedea..f89495cca3a 100644 --- a/src/doc/rustdoc/src/how-to-write-documentation.md +++ b/src/doc/rustdoc/src/how-to-write-documentation.md @@ -229,15 +229,13 @@ Example: ```md - [x] Complete task -- [ ] IncComplete task +- [ ] Incomplete task ``` -This will render as +This will render as: -<ul> - <li><input type="checkbox"></li> - <li><input type="checkbox" checked></li> -</ul> +> - [x] Complete task +> - [ ] Incomplete task See the specification for the [task list extension] for more details. diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index a6626679a7d..16b091eb255 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -294,6 +294,50 @@ warning: unclosed HTML tag `h1` warning: 2 warnings emitted ``` +## invalid_rust_codeblocks + +This lint **warns by default**. It detects Rust code blocks in documentation +examples that are invalid (e.g. empty, not parsable as Rust). For example: + +```rust +/// Empty code blocks (with and without the `rust` marker): +/// +/// ```rust +/// ``` +/// +/// Invalid syntax in code blocks: +/// +/// ```rust +/// '< +/// ``` +pub fn foo() {} +``` + +Which will give: + +```text +warning: Rust code block is empty + --> lint.rs:3:5 + | +3 | /// ```rust + | _____^ +4 | | /// ``` + | |_______^ + | + = note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default + +warning: could not parse code block as Rust code + --> lint.rs:8:5 + | +8 | /// ```rust + | _____^ +9 | | /// '< +10 | | /// ``` + | |_______^ + | + = note: error from rustc: unterminated character literal +``` + ## bare_urls This lint is **warn-by-default**. It detects URLs which are not links. diff --git a/src/doc/rustdoc/src/the-doc-attribute.md b/src/doc/rustdoc/src/the-doc-attribute.md index 52f2a3728fa..d192f7d5ce9 100644 --- a/src/doc/rustdoc/src/the-doc-attribute.md +++ b/src/doc/rustdoc/src/the-doc-attribute.md @@ -35,6 +35,13 @@ Which can feel more flexible. Note that this would generate this: but given that docs are rendered via Markdown, it will remove these newlines. +Another use case is for including external files as documentation: + +```rust,no_run +#[doc = include_str!("../README.md")] +# fn f() {} +``` + The `doc` attribute has more options though! These don't involve the text of the output, but instead, various aspects of the presentation of the output. We've split them into two kinds below: attributes that are useful at the diff --git a/src/doc/unstable-book/src/compiler-flags/force-warns.md b/src/doc/unstable-book/src/compiler-flags/force-warns.md new file mode 100644 index 00000000000..0a205be096c --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/force-warns.md @@ -0,0 +1,21 @@ +# `force-warns` + +The tracking issue for this feature is: [#85512](https://github.com/rust-lang/rust/issues/85512). + +------------------------ + +This feature allows you to cause any lint to produce a warning even if the lint has a different level by default or another level is set somewhere else. For instance, the `force-warns` option can be used to make a lint (e.g., `dead_code`) produce a warning even if that lint is allowed in code with `#![allow(dead_code)]`. + +## Example + +```rust,ignore (partial-example) +#![allow(dead_code)] + +fn dead_function() {} +// This would normally not produce a warning even though the +// function is not used, because dead code is being allowed + +fn main() {} +``` + +We can force a warning to be produced by providing `--force-warns dead_code` to rustc. diff --git a/src/doc/unstable-book/src/language-features/member-constraints.md b/src/doc/unstable-book/src/language-features/member-constraints.md deleted file mode 100644 index 3ba4a3e6b1f..00000000000 --- a/src/doc/unstable-book/src/language-features/member-constraints.md +++ /dev/null @@ -1,29 +0,0 @@ -# `member_constraints` - -The tracking issue for this feature is: [#61997] - -[#61997]: https://github.com/rust-lang/rust/issues/61997 - ------------------------- - -The `member_constraints` feature gate lets you use `impl Trait` syntax with -multiple unrelated lifetime parameters. - -A simple example is: - -```rust -#![feature(member_constraints)] - -trait Trait<'a, 'b> { } -impl<T> Trait<'_, '_> for T {} - -fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> { - (x, y) -} - -fn main() { } -``` - -Without the `member_constraints` feature gate, the above example is an -error because both `'a` and `'b` appear in the impl Trait bounds, but -neither outlives the other. diff --git a/src/etc/natvis/intrinsic.natvis b/src/etc/natvis/intrinsic.natvis index 030892a432b..89280149a03 100644 --- a/src/etc/natvis/intrinsic.natvis +++ b/src/etc/natvis/intrinsic.natvis @@ -149,4 +149,57 @@ <Synthetic Name="[...]"><DisplayString>...</DisplayString></Synthetic> </Expand> </Type> + <Type Name="enum$<*>"> + <Intrinsic Name="tag" Expression="variant0.variant$" /> + <DisplayString Condition="tag() == 0">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 1" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 2" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 3" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 4" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 5" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 6" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 7" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 8" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 9" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 10" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 11" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 12" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 13" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 14" Optional="true">{tag(),en}</DisplayString> + <DisplayString Condition="tag() == 15" Optional="true">{tag(),en}</DisplayString> + + <Expand> + <ExpandedItem Condition="tag() == 0">variant0</ExpandedItem> + <ExpandedItem Condition="tag() == 1" Optional="true">variant1</ExpandedItem> + <ExpandedItem Condition="tag() == 2" Optional="true">variant2</ExpandedItem> + <ExpandedItem Condition="tag() == 3" Optional="true">variant3</ExpandedItem> + <ExpandedItem Condition="tag() == 4" Optional="true">variant4</ExpandedItem> + <ExpandedItem Condition="tag() == 5" Optional="true">variant5</ExpandedItem> + <ExpandedItem Condition="tag() == 6" Optional="true">variant6</ExpandedItem> + <ExpandedItem Condition="tag() == 7" Optional="true">variant7</ExpandedItem> + <ExpandedItem Condition="tag() == 8" Optional="true">variant8</ExpandedItem> + <ExpandedItem Condition="tag() == 9" Optional="true">variant9</ExpandedItem> + <ExpandedItem Condition="tag() == 10" Optional="true">variant10</ExpandedItem> + <ExpandedItem Condition="tag() == 11" Optional="true">variant11</ExpandedItem> + <ExpandedItem Condition="tag() == 12" Optional="true">variant12</ExpandedItem> + <ExpandedItem Condition="tag() == 13" Optional="true">variant13</ExpandedItem> + <ExpandedItem Condition="tag() == 14" Optional="true">variant14</ExpandedItem> + <ExpandedItem Condition="tag() == 15" Optional="true">variant15</ExpandedItem> + </Expand> + </Type> + + <!-- $T1 is the name of the enum, $T2 is the low value of the dataful variant tag, + $T3 is the high value of the dataful variant tag, $T4 is the name of the dataful variant --> + <Type Name="enum$<*, *, *, *>"> + <Intrinsic Name="tag" Expression="discriminant" /> + <Intrinsic Name="is_dataful" Expression="tag() >= $T2 && tag() <= $T3" /> + <DisplayString Condition="is_dataful()">{"$T4",sb}({dataful_variant})</DisplayString> + <DisplayString Condition="!is_dataful()">{discriminant,en}</DisplayString> + <Expand> + <ExpandedItem Condition="is_dataful()">dataful_variant</ExpandedItem> + <Synthetic Condition="is_dataful()" Name="[variant]"> + <DisplayString>{"$T4",sb}</DisplayString> + </Synthetic> + </Expand> + </Type> </AutoVisualizer> diff --git a/src/etc/natvis/libcore.natvis b/src/etc/natvis/libcore.natvis index 9c3c26f5978..17667770520 100644 --- a/src/etc/natvis/libcore.natvis +++ b/src/etc/natvis/libcore.natvis @@ -14,14 +14,6 @@ </Expand> </Type> - <Type Name="core::option::Option<*>"> - <DisplayString Condition="RUST$ENUM$DISR == 0x0">None</DisplayString> - <DisplayString Condition="RUST$ENUM$DISR == 0x1">Some({__0})</DisplayString> - <Expand> - <Item Name="[value]" ExcludeView="simple" Condition="RUST$ENUM$DISR == 1">__0</Item> - </Expand> - </Type> - <Type Name="core::option::Option<*>" Priority="MediumLow"> <DisplayString Condition="*(void**)this == nullptr">None</DisplayString> <DisplayString>Some({($T1 *)this})</DisplayString> @@ -30,15 +22,6 @@ </Expand> </Type> - <Type Name="core::result::Result<*>"> - <DisplayString Condition="RUST$ENUM$DISR == 0x0">Ok({__0})</DisplayString> - <DisplayString Condition="RUST$ENUM$DISR == 0x1">Err({(*($T2*) &__0)})</DisplayString> - <Expand> - <Item Name="[value]" Condition="RUST$ENUM$DISR == 0x0">__0</Item> - <Item Name="[value]" Condition="RUST$ENUM$DISR == 0x1">(*($T2*) &__0)</Item> - </Expand> - </Type> - <Type Name="core::ptr::non_null::NonNull<*>"> <DisplayString>{(void*) pointer}</DisplayString> <Expand> diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index b816b9d7188..5ce75949457 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -10,7 +10,7 @@ path = "lib.rs" [dependencies] arrayvec = { version = "0.7", default-features = false } pulldown-cmark = { version = "0.8", default-features = false } -minifier = "0.0.39" +minifier = "0.0.41" rayon = { version = "0.3.0", package = "rustc-rayon" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/src/librustdoc/clean/auto_trait.rs b/src/librustdoc/clean/auto_trait.rs index 3bfc9fea62e..35ff57f85a5 100644 --- a/src/librustdoc/clean/auto_trait.rs +++ b/src/librustdoc/clean/auto_trait.rs @@ -561,7 +561,7 @@ impl<'a, 'tcx> AutoTraitFinder<'a, 'tcx> { } WherePredicate::EqPredicate { lhs, rhs } => { match lhs { - Type::QPath { name: left_name, ref self_type, ref trait_ } => { + Type::QPath { name: left_name, ref self_type, ref trait_, .. } => { let ty = &*self_type; match **trait_ { Type::ResolvedPath { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 6d05ac073cc..111827aacdf 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -527,7 +527,7 @@ fn build_static(cx: &mut DocContext<'_>, did: DefId, mutable: bool) -> clean::St } fn build_macro(cx: &mut DocContext<'_>, did: DefId, name: Symbol) -> clean::ItemKind { - let imported_from = cx.tcx.original_crate_name(did.krate); + let imported_from = cx.tcx.crate_name(did.krate); match cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())) { LoadedMacro::MacroDef(def, _) => { let matchers: Vec<Span> = if let ast::ItemKind::MacroDef(ref def) = def.kind { @@ -588,6 +588,7 @@ fn filter_non_trait_generics(trait_did: DefId, mut g: clean::Generics) -> clean: self_type: box clean::Generic(ref s), trait_: box clean::ResolvedPath { did, .. }, name: ref _name, + .. }, ref bounds, } => !(bounds.is_empty() || *s == kw::SelfUpper && did == trait_did), diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index feeb03b1b67..231f13adeb6 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -418,9 +418,11 @@ impl<'tcx> Clean<Type> for ty::ProjectionTy<'tcx> { GenericBound::TraitBound(t, _) => t.trait_, GenericBound::Outlives(_) => panic!("cleaning a trait got a lifetime"), }; + let self_type = self.self_ty().clean(cx); Type::QPath { name: cx.tcx.associated_item(self.item_def_id).ident.name, - self_type: box self.self_ty().clean(cx), + self_def_id: self_type.def_id(), + self_type: box self_type, trait_: box trait_, } } @@ -1104,7 +1106,7 @@ impl Clean<Item> for ty::AssocItem { .filter_map(|pred| { let (name, self_type, trait_, bounds) = match *pred { WherePredicate::BoundPredicate { - ty: QPath { ref name, ref self_type, ref trait_ }, + ty: QPath { ref name, ref self_type, ref trait_, .. }, ref bounds, } => (name, self_type, trait_, bounds), _ => return None, @@ -1282,16 +1284,15 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { let segments = if p.is_global() { &p.segments[1..] } else { &p.segments }; let trait_segments = &segments[..segments.len() - 1]; + let trait_def = cx.tcx.associated_item(p.res.def_id()).container.id(); let trait_path = self::Path { global: p.is_global(), - res: Res::Def( - DefKind::Trait, - cx.tcx.associated_item(p.res.def_id()).container.id(), - ), + res: Res::Def(DefKind::Trait, trait_def), segments: trait_segments.clean(cx), }; Type::QPath { name: p.segments.last().expect("segments were empty").ident.name, + self_def_id: Some(DefId::local(qself.hir_id.owner.local_def_index)), self_type: box qself.clean(cx), trait_: box resolve_type(cx, trait_path, hir_id), } @@ -1306,6 +1307,7 @@ fn clean_qpath(hir_ty: &hir::Ty<'_>, cx: &mut DocContext<'_>) -> Type { let trait_path = hir::Path { span, res, segments: &[] }.clean(cx); Type::QPath { name: segment.ident.name, + self_def_id: res.opt_def_id(), self_type: box qself.clean(cx), trait_: box resolve_type(cx, trait_path, hir_id), } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 859e525627a..ac2d58903c1 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -526,7 +526,6 @@ impl Item { crate fn is_crate(&self) -> bool { self.is_mod() && self.def_id.as_real().map_or(false, |did| did.index == CRATE_DEF_INDEX) } - crate fn is_mod(&self) -> bool { self.type_() == ItemType::Module } @@ -1519,6 +1518,7 @@ crate enum Type { QPath { name: Symbol, self_type: Box<Type>, + self_def_id: Option<DefId>, trait_: Box<Type>, }, @@ -1665,7 +1665,7 @@ impl Type { crate fn projection(&self) -> Option<(&Type, DefId, Symbol)> { let (self_, trait_, name) = match self { - QPath { self_type, trait_, name } => (self_type, trait_, name), + QPath { self_type, trait_, name, .. } => (self_type, trait_, name), _ => return None, }; let trait_did = match **trait_ { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 51a011cf197..2c31a502565 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -175,8 +175,9 @@ crate fn strip_type(ty: Type) -> Type { Type::BorrowedRef { lifetime, mutability, type_ } => { Type::BorrowedRef { lifetime, mutability, type_: Box::new(strip_type(*type_)) } } - Type::QPath { name, self_type, trait_ } => Type::QPath { + Type::QPath { name, self_type, trait_, self_def_id } => Type::QPath { name, + self_def_id, self_type: Box::new(strip_type(*self_type)), trait_: Box::new(strip_type(*trait_)), }, diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index b75e98ae16c..1b5a00dde59 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -6,8 +6,10 @@ use std::path::PathBuf; use std::str::FromStr; use rustc_data_structures::fx::FxHashMap; -use rustc_session::config::{self, parse_crate_types_from_list, parse_externs, CrateType}; -use rustc_session::config::{get_cmd_lint_options, host_triple, nightly_options}; +use rustc_session::config::{ + self, parse_crate_types_from_list, parse_externs, parse_target_triple, CrateType, +}; +use rustc_session::config::{get_cmd_lint_options, nightly_options}; use rustc_session::config::{CodegenOptions, DebuggingOptions, ErrorOutputType, Externs}; use rustc_session::getopts; use rustc_session::lint::Level; @@ -347,13 +349,6 @@ impl Options { return Err(0); } - if matches.opt_strs("print").iter().any(|opt| opt == "unversioned-files") { - for file in crate::html::render::FILES_UNVERSIONED.keys() { - println!("{}", file); - } - return Err(0); - } - let color = config::parse_color(&matches); let config::JsonConfig { json_rendered, json_unused_externs, .. } = config::parse_json(&matches); @@ -562,14 +557,7 @@ impl Options { } } - let target = - matches.opt_str("target").map_or(TargetTriple::from_triple(host_triple()), |target| { - if target.ends_with(".json") { - TargetTriple::TargetPath(PathBuf::from(target)) - } else { - TargetTriple::TargetTriple(target) - } - }); + let target = parse_target_triple(matches, error_format); let show_coverage = matches.opt_present("show-coverage"); @@ -640,7 +628,8 @@ impl Options { let generate_redirect_map = matches.opt_present("generate-redirect-map"); let show_type_layout = matches.opt_present("show-type-layout"); - let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); + let (lint_opts, describe_lints, lint_cap, _) = + get_cmd_lint_options(matches, error_format, &debugging_opts); Ok(Options { input, diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 8448b07d0be..d5213fd7711 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -18,7 +18,7 @@ use rustc_span::def_id::CRATE_DEF_INDEX; use rustc_target::spec::abi::Abi; use crate::clean::{ - self, utils::find_nearest_parent_module, ExternalCrate, FakeDefId, PrimitiveType, + self, utils::find_nearest_parent_module, ExternalCrate, FakeDefId, GetDefId, PrimitiveType, }; use crate::formats::item_type::ItemType; use crate::html::escape::Escape; @@ -836,10 +836,13 @@ fn fmt_type<'cx>( write!(f, "impl {}", print_generic_bounds(bounds, cx)) } } - clean::QPath { ref name, ref self_type, ref trait_ } => { + clean::QPath { ref name, ref self_type, ref trait_, ref self_def_id } => { let should_show_cast = match *trait_ { box clean::ResolvedPath { ref path, .. } => { - !path.segments.is_empty() && !self_type.is_self_type() + !path.segments.is_empty() + && self_def_id + .zip(trait_.def_id()) + .map_or(!self_type.is_self_type(), |(id, trait_)| id != trait_) } _ => true, }; diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index ec04c94dc11..429863f3635 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -119,7 +119,7 @@ crate fn render<T: Print, S: Print>( {after_content}\ <div id=\"rustdoc-vars\" data-root-path=\"{root_path}\" data-current-crate=\"{krate}\" \ data-search-index-js=\"{root_path}search-index{suffix}.js\" \ - data-search-js=\"{static_root_path}search{suffix}.js\"></div> + data-search-js=\"{static_root_path}search{suffix}.js\"></div>\ <script src=\"{static_root_path}main{suffix}.js\"></script>\ {extra_scripts}\ </body>\ @@ -235,6 +235,7 @@ crate fn redirect(url: &str) -> String { <html lang="en"> <head> <meta http-equiv="refresh" content="0;URL={url}"> + <title>Redirection</title> </head> <body> <p>Redirecting to <a href="{url}">{url}</a>...</p> diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs index 8676efd9fa8..d80b2db00ac 100644 --- a/src/librustdoc/html/render/context.rs +++ b/src/librustdoc/html/render/context.rs @@ -200,8 +200,15 @@ impl<'tcx> Context<'tcx> { ) }; let keywords = make_item_keywords(it); + let name; + let tyname_s = if it.is_crate() { + name = format!("{} crate", tyname); + name.as_str() + } else { + tyname.as_str() + }; let page = layout::Page { - css_class: tyname.as_str(), + css_class: tyname_s, root_path: &self.root_path(), static_root_path: self.shared.static_root_path.as_deref(), title: &title, diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index b807c5ccc47..10f5184e39a 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -33,7 +33,6 @@ mod print_item; mod write_shared; crate use context::*; -crate use write_shared::FILES_UNVERSIONED; use std::collections::VecDeque; use std::default::Default; @@ -509,7 +508,11 @@ fn document(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, parent: Option info!("Documenting {}", name); } document_item_info(w, cx, item, parent); - document_full_collapsible(w, item, cx); + if parent.is_none() { + document_full_collapsible(w, item, cx); + } else { + document_full(w, item, cx); + } } /// Render md_text as markdown. @@ -1348,8 +1351,11 @@ fn render_impl( } let w = if short_documented && trait_.is_some() { interesting } else { boring }; - if !doc_buffer.is_empty() { - w.write_str("<details class=\"rustdoc-toggle\" open><summary>"); + let toggled = !doc_buffer.is_empty(); + if toggled { + let method_toggle_class = + if item_type == ItemType::Method { " method-toggle" } else { "" }; + write!(w, "<details class=\"rustdoc-toggle{}\" open><summary>", method_toggle_class); } match *item.kind { clean::MethodItem(..) | clean::TyMethodItem(_) => { @@ -1363,7 +1369,11 @@ fn render_impl( }) }) .map(|item| format!("{}.{}", item.type_(), name)); - write!(w, "<h4 id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class,); + write!( + w, + "<div id=\"{}\" class=\"{}{} has-srclink\">", + id, item_type, in_trait_class, + ); w.write_str("<code>"); render_assoc_item( w, @@ -1382,13 +1392,17 @@ fn render_impl( ); write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); write_srclink(cx, item, w); - w.write_str("</h4>"); + w.write_str("</div>"); } } clean::TypedefItem(ref tydef, _) => { let source_id = format!("{}.{}", ItemType::AssocType, name); let id = cx.derive_id(source_id.clone()); - write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class); + write!( + w, + "<div id=\"{}\" class=\"{}{} has-srclink\"><code>", + id, item_type, in_trait_class + ); assoc_type( w, item, @@ -1400,12 +1414,16 @@ fn render_impl( ); w.write_str("</code>"); write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); - w.write_str("</h4>"); + w.write_str("</div>"); } clean::AssocConstItem(ref ty, ref default) => { let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); - write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class); + write!( + w, + "<div id=\"{}\" class=\"{}{} has-srclink\"><code>", + id, item_type, in_trait_class + ); assoc_const( w, item, @@ -1425,12 +1443,12 @@ fn render_impl( ); write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); write_srclink(cx, item, w); - w.write_str("</h4>"); + w.write_str("</div>"); } clean::AssocTypeItem(ref bounds, ref default) => { let source_id = format!("{}.{}", item_type, name); let id = cx.derive_id(source_id.clone()); - write!(w, "<h4 id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class); + write!(w, "<div id=\"{}\" class=\"{}{}\"><code>", id, item_type, in_trait_class,); assoc_type( w, item, @@ -1442,14 +1460,14 @@ fn render_impl( ); w.write_str("</code>"); write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id); - w.write_str("</h4>"); + w.write_str("</div>"); } clean::StrippedItem(..) => return, _ => panic!("can't make docs for trait item with name {:?}", item.name), } w.push_buffer(info_buffer); - if !doc_buffer.is_empty() { + if toggled { w.write_str("</summary>"); w.push_buffer(doc_buffer); w.push_str("</details>"); @@ -1535,24 +1553,33 @@ fn render_impl( } } let toggled = !impl_items.is_empty() || !default_impl_items.is_empty(); - let open_details = |close_tags: &mut String| { + let open_details = |close_tags: &mut String, is_collapsed: bool| { if toggled { close_tags.insert_str(0, "</details>"); - "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>" + if is_collapsed { + "<details class=\"rustdoc-toggle implementors-toggle\"><summary>" + } else { + "<details class=\"rustdoc-toggle implementors-toggle\" open><summary>" + } } else { "" } }; if render_mode == RenderMode::Normal { + let is_implementing_trait; let id = cx.derive_id(match i.inner_impl().trait_ { Some(ref t) => { + is_implementing_trait = true; if is_on_foreign_type { get_id_for_impl_on_foreign_type(&i.inner_impl().for_, t, cx) } else { format!("impl-{}", small_url_encode(format!("{:#}", t.print(cx)))) } } - None => "impl".to_string(), + None => { + is_implementing_trait = false; + "impl".to_string() + } }); let aliases = if aliases.is_empty() { String::new() @@ -1562,8 +1589,9 @@ fn render_impl( if let Some(use_absolute) = use_absolute { write!( w, - "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">", - open_details(&mut close_tags), + "{}<div id=\"{}\" class=\"impl has-srclink\"{}>\ + <code class=\"in-band\">", + open_details(&mut close_tags, is_implementing_trait), id, aliases ); @@ -1589,8 +1617,9 @@ fn render_impl( } else { write!( w, - "{}<h3 id=\"{}\" class=\"impl\"{}><code class=\"in-band\">{}</code>", - open_details(&mut close_tags), + "{}<div id=\"{}\" class=\"impl has-srclink\"{}>\ + <code class=\"in-band\">{}</code>", + open_details(&mut close_tags, is_implementing_trait), id, aliases, i.inner_impl().print(false, cx) @@ -1606,9 +1635,9 @@ fn render_impl( ); write_srclink(cx, &i.impl_item, w); if !toggled { - w.write_str("</h3>"); + w.write_str("</div>"); } else { - w.write_str("</h3></summary>"); + w.write_str("</div></summary>"); } if trait_.is_some() { @@ -1634,13 +1663,9 @@ fn render_impl( ); } } - if toggled { + if !default_impl_items.is_empty() || !impl_items.is_empty() { w.write_str("<div class=\"impl-items\">"); w.push_buffer(default_impl_items); - if trait_.is_some() && !impl_items.is_empty() { - w.write_str("<details class=\"undocumented\"><summary></summary>"); - close_tags.insert_str(0, "</details>"); - } w.push_buffer(impl_items); close_tags.insert_str(0, "</div>"); } @@ -1688,7 +1713,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { "<div class=\"block version\">\ <p>Version {}</p>\ </div>", - Escape(version) + Escape(version), ); } } @@ -1698,9 +1723,10 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { write!( buffer, "<a id=\"all-types\" href=\"all.html\"><p>See all {}'s items</p></a>", - it.name.as_ref().expect("crates always have a name") + it.name.as_ref().expect("crates always have a name"), ); } + match *it.kind { clean::StructItem(ref s) => sidebar_struct(cx, buffer, it, s), clean::TraitItem(ref t) => sidebar_trait(cx, buffer, it, t), @@ -1710,7 +1736,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { clean::TypedefItem(_, _) => sidebar_typedef(cx, buffer, it), clean::ModuleItem(ref m) => sidebar_module(buffer, &m.items), clean::ForeignTypeItem => sidebar_foreign_type(cx, buffer, it), - _ => (), + _ => {} } // The sidebar is designed to display sibling functions, modules and @@ -1721,22 +1747,24 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { // as much HTML as possible in order to allow non-JS-enabled browsers // to navigate the documentation (though slightly inefficiently). - buffer.write_str("<p class=\"location\">"); - for (i, name) in cx.current.iter().take(parentlen).enumerate() { - if i > 0 { - buffer.write_str("::<wbr>"); + if !it.is_mod() { + buffer.write_str("<p class=\"location\">Other items in<br>"); + for (i, name) in cx.current.iter().take(parentlen).enumerate() { + if i > 0 { + buffer.write_str("::<wbr>"); + } + write!( + buffer, + "<a href=\"{}index.html\">{}</a>", + &cx.root_path()[..(cx.current.len() - i - 1) * 3], + *name + ); } - write!( - buffer, - "<a href=\"{}index.html\">{}</a>", - &cx.root_path()[..(cx.current.len() - i - 1) * 3], - *name - ); + buffer.write_str("</p>"); } - buffer.write_str("</p>"); // Sidebar refers to the enclosing module, not this module. - let relpath = if it.is_mod() { "../" } else { "" }; + let relpath = if it.is_mod() && parentlen != 0 { "./" } else { "" }; write!( buffer, "<div id=\"sidebar-vars\" data-name=\"{name}\" data-ty=\"{ty}\" data-relpath=\"{path}\">\ @@ -1745,17 +1773,7 @@ fn print_sidebar(cx: &Context<'_>, it: &clean::Item, buffer: &mut Buffer) { ty = it.type_(), path = relpath ); - - if parentlen == 0 { - write!( - buffer, - "<script defer src=\"{}sidebar-items{}.js\"></script>", - relpath, cx.shared.resource_suffix - ); - } else { - write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath); - } - + write!(buffer, "<script defer src=\"{}sidebar-items.js\"></script>", relpath); // Closes sidebar-elems div. buffer.write_str("</div>"); } @@ -2263,8 +2281,8 @@ fn sidebar_enum(cx: &Context<'_>, buf: &mut Buffer, it: &clean::Item, e: &clean: } } -fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { - match *ty { +fn item_ty_to_strs(ty: ItemType) -> (&'static str, &'static str) { + match ty { ItemType::ExternCrate | ItemType::Import => ("reexports", "Re-exports"), ItemType::Module => ("modules", "Modules"), ItemType::Struct => ("structs", "Structs"), @@ -2296,10 +2314,14 @@ fn item_ty_to_strs(ty: &ItemType) -> (&'static str, &'static str) { fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) { let mut sidebar = String::new(); + // Re-exports are handled a bit differently because they can be extern crates or imports. if items.iter().any(|it| { - it.type_() == ItemType::ExternCrate || (it.type_() == ItemType::Import && !it.is_stripped()) + it.name.is_some() + && (it.type_() == ItemType::ExternCrate + || (it.type_() == ItemType::Import && !it.is_stripped())) }) { - sidebar.push_str("<li><a href=\"#reexports\">Re-exports</a></li>"); + let (id, name) = item_ty_to_strs(ItemType::Import); + sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name)); } // ordering taken from item_module, reorder, where it prioritized elements in a certain order @@ -2326,13 +2348,9 @@ fn sidebar_module(buf: &mut Buffer, items: &[clean::Item]) { ItemType::ForeignType, ItemType::Keyword, ] { - if items.iter().any(|it| !it.is_stripped() && it.type_() == myty) { - let (short, name) = item_ty_to_strs(&myty); - sidebar.push_str(&format!( - "<li><a href=\"#{id}\">{name}</a></li>", - id = short, - name = name - )); + if items.iter().any(|it| !it.is_stripped() && it.type_() == myty && it.name.is_some()) { + let (id, name) = item_ty_to_strs(myty); + sidebar.push_str(&format!("<li><a href=\"#{}\">{}</a></li>", id, name)); } } diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs index ff639cb2924..1c5d9a26441 100644 --- a/src/librustdoc/html/render/print_item.rs +++ b/src/librustdoc/html/render/print_item.rs @@ -75,13 +75,14 @@ pub(super) fn print_item(cx: &Context<'_>, item: &clean::Item, buf: &mut Buffer, ); } } - write!(buf, "<a class=\"{}\" href=\"\">{}</a>", item.type_(), item.name.as_ref().unwrap()); + write!(buf, "<a class=\"{}\" href=\"#\">{}</a>", item.type_(), item.name.as_ref().unwrap()); write!( buf, "<button id=\"copy-path\" onclick=\"copy_path(this)\">\ <img src=\"{static_root_path}clipboard{suffix}.svg\" \ width=\"19\" height=\"18\" \ - alt=\"Copy item import\">\ + alt=\"Copy item import\" \ + title=\"Copy item import to clipboard\">\ </button>", static_root_path = page.get_static_root_path(), suffix = page.resource_suffix, @@ -262,7 +263,7 @@ fn item_module(w: &mut Buffer, cx: &Context<'_>, item: &clean::Item, items: &[cl w.write_str("</table>"); } curty = myty; - let (short, name) = item_ty_to_strs(&myty.unwrap()); + let (short, name) = item_ty_to_strs(myty.unwrap()); write!( w, "<h2 id=\"{id}\" class=\"section-header\">\ @@ -578,13 +579,23 @@ fn item_trait(w: &mut Buffer, cx: &Context<'_>, it: &clean::Item, t: &clean::Tra info!("Documenting {} on {:?}", name, t.name); let item_type = m.type_(); let id = cx.derive_id(format!("{}.{}", item_type, name)); - write!(w, "<h3 id=\"{id}\" class=\"method\"><code>", id = id,); + let mut content = Buffer::empty_from(w); + document(&mut content, cx, m, Some(t)); + let toggled = !content.is_empty(); + if toggled { + write!(w, "<details class=\"rustdoc-toggle\" open><summary>"); + } + write!(w, "<div id=\"{}\" class=\"method has-srclink\"><code>", id); render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl, cx); w.write_str("</code>"); render_stability_since(w, m, t, cx.tcx()); write_srclink(cx, m, w); - w.write_str("</h3>"); - document(w, cx, m, Some(t)); + w.write_str("</div>"); + if toggled { + write!(w, "</summary>"); + w.push_buffer(content); + write!(w, "</details>"); + } } if !types.is_empty() { @@ -1501,7 +1512,7 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { w.write_str( "Non-exhaustive structs could have additional fields added in future. \ Therefore, non-exhaustive structs cannot be constructed in external crates \ - using the traditional <code>Struct {{ .. }}</code> syntax; cannot be \ + using the traditional <code>Struct { .. }</code> syntax; cannot be \ matched against without a wildcard <code>..</code>; and \ struct update syntax will not work.", ); diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index bd781e7b741..a4188e6b203 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -18,7 +18,7 @@ use crate::docfs::PathError; use crate::error::Error; use crate::html::{layout, static_files}; -crate static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| { +static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| { map! { "FiraSans-Regular.woff2" => static_files::fira_sans::REGULAR2, "FiraSans-Medium.woff2" => static_files::fira_sans::MEDIUM2, @@ -33,6 +33,8 @@ crate static FILES_UNVERSIONED: Lazy<FxHashMap<&str, &[u8]>> = Lazy::new(|| { "SourceCodePro-Semibold.ttf.woff" => static_files::source_code_pro::SEMIBOLD, "SourceCodePro-It.ttf.woff" => static_files::source_code_pro::ITALIC, "SourceCodePro-LICENSE.txt" => static_files::source_code_pro::LICENSE, + "noto-sans-kr-v13-korean-regular.woff" => static_files::noto_sans_kr::REGULAR, + "noto-sans-kr-v13-korean-regular-LICENSE.txt" => static_files::noto_sans_kr::LICENSE, "LICENSE-MIT.txt" => static_files::LICENSE_MIT, "LICENSE-APACHE.txt" => static_files::LICENSE_APACHE, "COPYRIGHT.txt" => static_files::COPYRIGHT, @@ -225,7 +227,6 @@ pub(super) fn write_shared( )?; write_minify("search.js", static_files::SEARCH_JS)?; write_minify("settings.js", static_files::SETTINGS_JS)?; - write_minify("sidebar-items.js", static_files::sidebar::ITEMS)?; if cx.shared.include_sources { write_minify("source-script.js", static_files::sidebar::SOURCE_SCRIPT)?; diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index be30871ea4c..1a15a444a70 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -161,7 +161,7 @@ function hideThemeButtonState() { outputElement: function() { return document.getElementById("search"); }, - title: null, + title: document.title, titleBeforeSearch: document.title, timeout: null, // On the search screen, so you remain on the last tab you opened. @@ -170,7 +170,8 @@ function hideThemeButtonState() { // 1 for "In Parameters" // 2 for "In Return Types" currentTab: 0, - mouseMovedAfterSearch: true, + // tab and back preserves the element that was focused. + focusedByTab: [null, null, null], clearInputTimeout: function() { if (searchState.timeout !== null) { clearTimeout(searchState.timeout); @@ -262,10 +263,6 @@ function hideThemeButtonState() { search_input.placeholder = searchState.input.origPlaceholder; }); - document.addEventListener("mousemove", function() { - searchState.mouseMovedAfterSearch = true; - }); - search_input.removeAttribute('disabled'); // `crates{version}.js` should always be loaded before this script, so we can use it @@ -428,9 +425,9 @@ function hideThemeButtonState() { function handleEscape(ev) { var help = getHelpElement(false); var search = searchState.outputElement(); - if (!hasClass(help, "hidden")) { + if (help && !hasClass(help, "hidden")) { displayHelp(false, ev, help); - } else if (!hasClass(search, "hidden")) { + } else if (search && !hasClass(search, "hidden")) { searchState.clearInputTimeout(); ev.preventDefault(); searchState.hideResults(search); @@ -564,41 +561,40 @@ function hideThemeButtonState() { } }()); - function addSidebarCrates(crates) { - // Draw a convenient sidebar of known crates if we have a listing - if (window.rootPath === "../" || window.rootPath === "./") { - var sidebar = document.getElementsByClassName("sidebar-elems")[0]; - if (sidebar) { - var div = document.createElement("div"); - div.className = "block crate"; - div.innerHTML = "<h3>Crates</h3>"; - var ul = document.createElement("ul"); - div.appendChild(ul); - - for (var i = 0; i < crates.length; ++i) { - var klass = "crate"; - if (window.rootPath !== "./" && crates[i] === window.currentCrate) { - klass += " current"; - } - var link = document.createElement("a"); - link.href = window.rootPath + crates[i] + "/index.html"; - link.className = klass; - link.textContent = crates[i]; - - var li = document.createElement("li"); - li.appendChild(link); - ul.appendChild(li); - } - sidebar.appendChild(div); - } - } - } - // delayed sidebar rendering. window.initSidebarItems = function(items) { var sidebar = document.getElementsByClassName("sidebar-elems")[0]; var current = window.sidebarCurrent; + function addSidebarCrates(crates) { + if (!hasClass(document.body, "crate")) { + // We only want to list crates on the crate page. + return; + } + // Draw a convenient sidebar of known crates if we have a listing + var div = document.createElement("div"); + div.className = "block crate"; + div.innerHTML = "<h3>Crates</h3>"; + var ul = document.createElement("ul"); + div.appendChild(ul); + + for (var i = 0; i < crates.length; ++i) { + var klass = "crate"; + if (window.rootPath !== "./" && crates[i] === window.currentCrate) { + klass += " current"; + } + var link = document.createElement("a"); + link.href = window.rootPath + crates[i] + "/index.html"; + link.className = klass; + link.textContent = crates[i]; + + var li = document.createElement("li"); + li.appendChild(link); + ul.appendChild(li); + } + sidebar.appendChild(div); + } + function block(shortty, longty) { var filtered = items[shortty]; if (!filtered) { @@ -637,28 +633,32 @@ function hideThemeButtonState() { ul.appendChild(li); } div.appendChild(ul); - if (sidebar) { - sidebar.appendChild(div); - } + sidebar.appendChild(div); } - block("primitive", "Primitive Types"); - block("mod", "Modules"); - block("macro", "Macros"); - block("struct", "Structs"); - block("enum", "Enums"); - block("union", "Unions"); - block("constant", "Constants"); - block("static", "Statics"); - block("trait", "Traits"); - block("fn", "Functions"); - block("type", "Type Definitions"); - block("foreigntype", "Foreign Types"); - block("keyword", "Keywords"); - block("traitalias", "Trait Aliases"); - - // `crates{version}.js` should always be loaded before this script, so we can use it safely. - addSidebarCrates(window.ALL_CRATES); + if (sidebar) { + var isModule = hasClass(document.body, "mod"); + if (!isModule) { + block("primitive", "Primitive Types"); + block("mod", "Modules"); + block("macro", "Macros"); + block("struct", "Structs"); + block("enum", "Enums"); + block("union", "Unions"); + block("constant", "Constants"); + block("static", "Statics"); + block("trait", "Traits"); + block("fn", "Functions"); + block("type", "Type Definitions"); + block("foreigntype", "Foreign Types"); + block("keyword", "Keywords"); + block("traitalias", "Trait Aliases"); + } + + // `crates{version}.js` should always be loaded before this script, so we can use + // it safely. + addSidebarCrates(window.ALL_CRATES); + } }; window.register_implementors = function(imp) { @@ -767,138 +767,6 @@ function hideThemeButtonState() { innerToggle.children[0].innerText = labelForToggleButton(sectionIsCollapsed); } - function collapseDocs(toggle, mode) { - if (!toggle || !toggle.parentNode) { - return; - } - - function adjustToggle(arg) { - return function(e) { - if (hasClass(e, "toggle-label")) { - if (arg) { - e.style.display = "inline-block"; - } else { - e.style.display = "none"; - } - } - if (hasClass(e, "inner")) { - e.innerHTML = labelForToggleButton(arg); - } - }; - } - - function implHider(addOrRemove, fullHide) { - return function(n) { - var shouldHide = - fullHide || - hasClass(n, "method") || - hasClass(n, "associatedconstant"); - if (shouldHide || hasClass(n, "type")) { - if (shouldHide) { - if (addOrRemove) { - addClass(n, "hidden-by-impl-hider"); - } else { - removeClass(n, "hidden-by-impl-hider"); - } - } - var ns = n.nextElementSibling; - while (ns && (hasClass(ns, "docblock") || hasClass(ns, "item-info"))) { - if (addOrRemove) { - addClass(ns, "hidden-by-impl-hider"); - } else { - removeClass(ns, "hidden-by-impl-hider"); - } - ns = ns.nextElementSibling; - } - } - }; - } - - var relatedDoc; - var action = mode; - if (!hasClass(toggle.parentNode, "impl")) { - relatedDoc = toggle.parentNode.nextElementSibling; - if (hasClass(relatedDoc, "item-info")) { - relatedDoc = relatedDoc.nextElementSibling; - } - if (hasClass(relatedDoc, "docblock")) { - if (mode === "toggle") { - if (hasClass(relatedDoc, "hidden-by-usual-hider")) { - action = "show"; - } else { - action = "hide"; - } - } - if (action === "hide") { - addClass(relatedDoc, "hidden-by-usual-hider"); - onEachLazy(toggle.childNodes, adjustToggle(true)); - addClass(toggle.parentNode, "collapsed"); - } else if (action === "show") { - removeClass(relatedDoc, "hidden-by-usual-hider"); - removeClass(toggle.parentNode, "collapsed"); - onEachLazy(toggle.childNodes, adjustToggle(false)); - } - } - } else { - // we are collapsing the impl block(s). - - var parentElem = toggle.parentNode; - relatedDoc = parentElem; - var docblock = relatedDoc.nextElementSibling; - - while (!hasClass(relatedDoc, "impl-items")) { - relatedDoc = relatedDoc.nextElementSibling; - } - - if (!relatedDoc && !hasClass(docblock, "docblock")) { - return; - } - - // Hide all functions, but not associated types/consts. - - if (mode === "toggle") { - if (hasClass(relatedDoc, "fns-now-collapsed") || - hasClass(docblock, "hidden-by-impl-hider")) { - action = "show"; - } else { - action = "hide"; - } - } - - var dontApplyBlockRule = toggle.parentNode.parentNode.id !== "main"; - if (action === "show") { - removeClass(relatedDoc, "fns-now-collapsed"); - // Stability/deprecation/portability information is never hidden. - if (!hasClass(docblock, "item-info")) { - removeClass(docblock, "hidden-by-usual-hider"); - } - onEachLazy(toggle.childNodes, adjustToggle(false, dontApplyBlockRule)); - onEachLazy(relatedDoc.childNodes, implHider(false, dontApplyBlockRule)); - } else if (action === "hide") { - addClass(relatedDoc, "fns-now-collapsed"); - // Stability/deprecation/portability information should be shown even when detailed - // info is hidden. - if (!hasClass(docblock, "item-info")) { - addClass(docblock, "hidden-by-usual-hider"); - } - onEachLazy(toggle.childNodes, adjustToggle(true, dontApplyBlockRule)); - onEachLazy(relatedDoc.childNodes, implHider(true, dontApplyBlockRule)); - } - } - } - - function collapseNonInherent(e) { - // inherent impl ids are like "impl" or impl-<number>'. - // they will never be hidden by default. - var n = e.parentElement; - if (n.id.match(/^impl(?:-\d+)?$/) === null) { - // Automatically minimize all non-inherent impls - if (hasClass(n, "impl")) { - collapseDocs(e, "hide"); - } - } - } - function insertAfter(newNode, referenceNode) { referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } @@ -911,53 +779,36 @@ function hideThemeButtonState() { var hideMethodDocs = getSettingValue("auto-hide-method-docs") === "true"; var hideImplementors = getSettingValue("auto-collapse-implementors") !== "false"; + var hideImplementations = getSettingValue("auto-hide-trait-implementations") !== "false"; var hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false"; - var impl_list = document.getElementById("trait-implementations-list"); - if (impl_list !== null) { - onEachLazy(impl_list.getElementsByClassName("rustdoc-toggle"), function(e) { - collapseNonInherent(e); - }); + function openImplementors(id) { + var list = document.getElementById(id); + if (list !== null) { + onEachLazy(list.getElementsByClassName("implementors-toggle"), function(e) { + e.open = true; + }); + } } - var blanket_list = document.getElementById("blanket-implementations-list"); - if (blanket_list !== null) { - onEachLazy(blanket_list.getElementsByClassName("rustdoc-toggle"), function(e) { - collapseNonInherent(e); - }); + if (!hideImplementations) { + openImplementors("trait-implementations-list"); + openImplementors("blanket-implementations-list"); } - if (hideMethodDocs) { - onEachLazy(document.getElementsByClassName("method"), function(e) { - var toggle = e.parentNode; - if (toggle) { - toggle = toggle.parentNode; - } - if (toggle && toggle.tagName === "DETAILS") { - toggle.open = false; - } - }); + if (!hideImplementors) { + openImplementors("implementors-list"); } - onEachLazy(document.getElementsByTagName("details"), function (e) { - var showLargeItem = !hideLargeItemContents && hasClass(e, "type-contents-toggle"); - var showImplementor = !hideImplementors && hasClass(e, "implementors-toggle"); - if (showLargeItem || showImplementor) { + onEachLazy(document.getElementsByClassName("rustdoc-toggle"), function (e) { + if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) { e.open = true; } - }); - - var currentType = document.getElementsByClassName("type-decl")[0]; - if (currentType) { - currentType = currentType.getElementsByClassName("rust")[0]; - if (currentType) { - onEachLazy(currentType.classList, function(item) { - if (item !== "main") { - return true; - } - }); + if (hideMethodDocs && hasClass(e, "method-toggle")) { + e.open = false; } - } + + }); var pageId = getPageId(); if (pageId !== null) { @@ -1064,7 +915,7 @@ function hideThemeButtonState() { ["T", "Focus the theme picker menu"], ["↑", "Move up in search results"], ["↓", "Move down in search results"], - ["ctrl + ↑ / ↓", "Switch result tab"], + ["← / →", "Switch result tab (when results focused)"], ["⏎", "Go to active search result"], ["+", "Expand all sections"], ["-", "Collapse all sections"], diff --git a/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt new file mode 100644 index 00000000000..922d5fdc18d --- /dev/null +++ b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular-LICENSE.txt @@ -0,0 +1,93 @@ +Copyright 2014, 2015 Adobe Systems Incorporated (http://www.adobe.com/), with Reserved Font Name 'Source'. All Rights Reserved. Source is a trademark of Adobe Systems Incorporated in the United States and/or other countries. + +This Font Software is licensed under the SIL Open Font License, Version 1.1. + +This license is copied below, and is also available with a FAQ at: http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff new file mode 100644 index 00000000000..01d6b6b5466 --- /dev/null +++ b/src/librustdoc/html/static/noto-sans-kr-v13-korean-regular.woff Binary files differdiff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index e2e1aefa4a8..d3f8a7aa67d 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -66,6 +66,14 @@ font-display: swap; } +/* Avoid using legacy CJK serif fonts in Windows like Batang */ +@font-face { + font-family: 'Noto Sans KR'; + src: url("noto-sans-kr-v13-korean-regular.woff") format("woff"); + font-display: swap; + unicode-range: U+A960-A97F, U+AC00-D7AF, U+D7B0-D7FF; +} + * { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; @@ -90,7 +98,7 @@ html { /* General structure and fonts */ body { - font: 16px/1.4 "Source Serif 4", serif; + font: 16px/1.4 "Source Serif 4", "Noto Sans KR", serif; margin: 0; position: relative; padding: 10px 15px 20px 15px; @@ -109,8 +117,7 @@ h2 { h3 { font-size: 1.3em; } -h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod):not(.notable), -h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) { +h1, h2, h3, h4 { font-weight: 500; margin: 20px 0 15px 0; padding-bottom: 6px; @@ -127,29 +134,38 @@ h1.fqn { h1.fqn > .in-band > a:hover { text-decoration: underline; } -h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), -h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant):not(.associatedtype) { +h2, h3, h4 { border-bottom: 1px solid; } -h3.impl, h3.method, h4.method, h3.type, h4.type, h4.associatedconstant, h4.associatedtype { +.impl, .method, +.type, .associatedconstant, +.associatedtype { flex-basis: 100%; font-weight: 600; margin-top: 16px; margin-bottom: 10px; position: relative; } -h3.impl, h3.method, h4.method.trait-impl, h3.type, -h4.type.trait-impl, h4.associatedconstant.trait-impl, h4.associatedtype.trait-impl { +.impl, .method.trait-impl, +.type.trait-impl, +.associatedconstant.trait-impl, +.associatedtype.trait-impl { padding-left: 15px; } +div.impl-items > div { + padding-left: 0; +} + h1, h2, h3, h4, -.sidebar, a.source, .search-input, .content table td:first-child > a, -div.item-list .out-of-band, +.sidebar, a.source, .search-input, .search-results .result-name, +.content table td:first-child > a, +div.item-list .out-of-band, span.since, #source-sidebar, #sidebar-toggle, details.rustdoc-toggle > summary::before, details.undocumented > summary::before, -.content ul.crate a.crate, +div.impl-items > div:not(.docblock):not(.item-info), +.content ul.crate a.crate, a.srclink, /* This selector is for the items listed in the "all items" page. */ #main > ul.docblock > li > a { font-family: "Fira Sans", Arial, sans-serif; @@ -295,17 +311,18 @@ nav.sub { border: none; } -.location a:first-child { +.location a:first-of-type { font-weight: 500; } +.location a:hover { + text-decoration: underline; +} .block { padding: 0; margin-bottom: 14px; } .block h2, .block h3 { - margin-top: 0; - margin-bottom: 8px; text-align: center; } .block ul, .block li { @@ -427,9 +444,13 @@ nav.sub { border-bottom: 1px solid; } -#main > .docblock h1 { font-size: 1.3em; } -#main > .docblock h2 { font-size: 1.15em; } -#main > .docblock h3, #main > .docblock h4, #main > .docblock h5 { font-size: 1em; } +.top-doc .docblock h1 { font-size: 1.3em; } +.top-doc .docblock h2 { font-size: 1.15em; } +.top-doc .docblock h3, +.top-doc .docblock h4, +.top-doc .docblock h5 { + font-size: 1em; +} .docblock h1 { font-size: 1em; } .docblock h2 { font-size: 0.95em; } @@ -449,15 +470,7 @@ nav.sub { font-weight: normal; } -h3.impl > .out-of-band { - font-size: 21px; -} - -h4.method > .out-of-band { - font-size: 19px; -} - -h4 > code, h3 > code, .invisible > code { +.method > code, .trait-impl > code, .invisible > code { max-width: calc(100% - 41px); display: block; } @@ -530,7 +543,7 @@ h4 > code, h3 > code, .invisible > code { } .content .multi-column li { width: 100%; display: inline-block; } -.content .method { +.content > .methods > .method { font-size: 1em; position: relative; } @@ -542,7 +555,7 @@ h4 > code, h3 > code, .invisible > code { font-size: 0.8em; } -.content .methods > div:not(.notable-traits):not(.methods) { +.content .methods > div:not(.notable-traits):not(.method) { margin-left: 40px; margin-bottom: 15px; } @@ -551,9 +564,6 @@ h4 > code, h3 > code, .invisible > code { margin-left: 20px; margin-top: -34px; } -.content .docblock > .impl-items > h4 { - border-bottom: 0; -} .content .docblock >.impl-items .table-display { margin: 0; } @@ -675,7 +685,8 @@ a { text-decoration: underline; } -.invisible > .srclink, h4 > code + .srclink, h3 > code + .srclink { +.invisible > .srclink, +.method > code + .srclink { position: absolute; top: 0; right: 0; @@ -748,41 +759,47 @@ a { outline: 0; } -.search-results .desc { +.search-results { + display: none; + padding-bottom: 2em; +} + +.search-results.active { + display: block; + /* prevent overhanging tabs from moving the first result */ + clear: both; +} + +.search-results .desc > span { white-space: nowrap; text-overflow: ellipsis; overflow: hidden; display: block; } -.search-results a { +.search-results > a { display: block; + width: 100%; + /* A little margin ensures the browser's outlining of focused links has room to display. */ + margin-left: 2px; + margin-right: 2px; + border-bottom: 1px solid #aaa3; } -.content .search-results td:first-child { - padding-right: 0; - width: 50%; -} -.content .search-results td:first-child a { - padding-right: 10px; -} -.content .search-results td:first-child a:after { - clear: both; - content: ""; - display: block; -} -.content .search-results td:first-child a span { - float: left; +.search-results > a > div { + display: flex; + flex-flow: row wrap; } -tr.result span.primitive::after { - content: ' (primitive type)'; - font-style: italic; +.search-results .result-name, .search-results div.desc, .search-results .result-description { + width: 50%; +} +.search-results .result-name { + padding-right: 1em; } -tr.result span.keyword::after { - content: ' (keyword)'; - font-style: italic; +.search-results .result-name > span { + display: inline-block; } body.blur > :not(#help) { @@ -904,7 +921,7 @@ body.blur > :not(#help) { flex-grow: 1; } -.impl-items h4, h4.impl, h3.impl, .methods h3 { +.has-srclink { display: flex; flex-basis: 100%; font-size: 16px; @@ -1115,6 +1132,13 @@ a.test-arrow:hover{ margin: 0; } +.notable-traits .notable { + margin: 0; + margin-bottom: 13px; + font-size: 19px; + font-weight: 600; +} + .notable-traits .docblock code.content{ margin: 0; padding: 0; @@ -1134,6 +1158,11 @@ pre.rust { .search-failed { text-align: center; margin-top: 20px; + display: none; +} + +.search-failed.active { + display: block; } .search-failed > ul { @@ -1173,12 +1202,6 @@ pre.rust { margin-left: 5px; } -h4 > .notable-traits { - position: absolute; - left: -44px; - top: 2px; -} - #all-types { text-align: center; border: 1px solid; @@ -1262,12 +1285,11 @@ h4 > .notable-traits { } #copy-path { + background: initial; margin-left: 10px; padding: 0; padding-left: 2px; -} -#copy-path> img { - margin-bottom: 2px; + border: 0; } #theme-choices { @@ -1293,14 +1315,6 @@ h4 > .notable-traits { border-top: 1px solid; } - - -h3.notable { - margin: 0; - margin-bottom: 13px; - font-size: 19px; -} - kbd { display: inline-block; padding: 3px 5px; @@ -1445,13 +1459,12 @@ details.rustdoc-toggle > summary.hideme::before { details.rustdoc-toggle > summary:not(.hideme)::before { position: absolute; left: -23px; - top: initial; + top: 3px; } .impl-items > details.rustdoc-toggle > summary:not(.hideme)::before, .undocumented > details.rustdoc-toggle > summary:not(.hideme)::before { position: absolute; - top: 3px; left: -2px; } @@ -1593,10 +1606,6 @@ details.undocumented[open] > summary::before { padding: 0; } - .content h4 > .out-of-band { - position: inherit; - } - #search { margin-left: 0; } @@ -1616,7 +1625,7 @@ details.undocumented[open] > summary::before { z-index: 1; } - h4 > .notable-traits { + .notable-traits { position: absolute; left: -22px; top: 24px; @@ -1724,6 +1733,18 @@ details.undocumented[open] > summary::before { .search-container > div { width: calc(100% - 32px); } + + /* Display an alternating layout on tablets and phones */ + .search-results > a { + border-bottom: 1px solid #aaa9; + padding: 5px 0px; + } + .search-results .result-name, .search-results div.desc, .search-results .result-description { + width: 100%; + } + .search-results div.desc, .search-results .result-description { + padding-left: 2em; + } } @media print { diff --git a/src/librustdoc/html/static/search.js b/src/librustdoc/html/static/search.js index c53b3d5f14b..b3242bf4df9 100644 --- a/src/librustdoc/html/static/search.js +++ b/src/librustdoc/html/static/search.js @@ -51,9 +51,9 @@ function printTab(nb) { }); onEachLazy(document.getElementById("results").childNodes, function(elem) { if (nb === 0) { - elem.style.display = ""; + addClass(elem, "active"); } else { - elem.style.display = "none"; + removeClass(elem, "active"); } nb -= 1; }); @@ -878,106 +878,22 @@ window.initSearch = function(rawSearchIndex) { }; } - function initSearchNav() { - var hoverTimeout; - - var click_func = function(e) { - var el = e.target; - // to retrieve the real "owner" of the event. - while (el.tagName !== "TR") { - el = el.parentNode; - } - var dst = e.target.getElementsByTagName("a"); - if (dst.length < 1) { - return; - } - dst = dst[0]; - if (window.location.pathname === dst.pathname) { - searchState.hideResults(); - document.location.href = dst.href; - } - }; - var mouseover_func = function(e) { - if (searchState.mouseMovedAfterSearch) { - var el = e.target; - // to retrieve the real "owner" of the event. - while (el.tagName !== "TR") { - el = el.parentNode; - } - clearTimeout(hoverTimeout); - hoverTimeout = setTimeout(function() { - onEachLazy(document.getElementsByClassName("search-results"), function(e) { - onEachLazy(e.getElementsByClassName("result"), function(i_e) { - removeClass(i_e, "highlighted"); - }); - }); - addClass(el, "highlighted"); - }, 20); - } - }; - onEachLazy(document.getElementsByClassName("search-results"), function(e) { - onEachLazy(e.getElementsByClassName("result"), function(i_e) { - i_e.onclick = click_func; - i_e.onmouseover = mouseover_func; - }); - }); - - searchState.input.onkeydown = function(e) { - // "actives" references the currently highlighted item in each search tab. - // Each array in "actives" represents a tab. - var actives = [[], [], []]; - // "current" is used to know which tab we're looking into. - var current = 0; - onEachLazy(document.getElementById("results").childNodes, function(e) { - onEachLazy(e.getElementsByClassName("highlighted"), function(h_e) { - actives[current].push(h_e); - }); - current += 1; - }); - var SHIFT = 16; - var CTRL = 17; - var ALT = 18; + function nextTab(direction) { + var next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length; + searchState.focusedByTab[searchState.currentTab] = document.activeElement; + printTab(next); + focusSearchResult(); + } - var currentTab = searchState.currentTab; - if (e.which === 38) { // up - if (e.ctrlKey) { // Going through result tabs. - printTab(currentTab > 0 ? currentTab - 1 : 2); - } else { - if (!actives[currentTab].length || - !actives[currentTab][0].previousElementSibling) { - return; - } - addClass(actives[currentTab][0].previousElementSibling, "highlighted"); - removeClass(actives[currentTab][0], "highlighted"); - } - e.preventDefault(); - } else if (e.which === 40) { // down - if (e.ctrlKey) { // Going through result tabs. - printTab(currentTab > 1 ? 0 : currentTab + 1); - } else if (!actives[currentTab].length) { - var results = document.getElementById("results").childNodes; - if (results.length > 0) { - var res = results[currentTab].getElementsByClassName("result"); - if (res.length > 0) { - addClass(res[0], "highlighted"); - } - } - } else if (actives[currentTab][0].nextElementSibling) { - addClass(actives[currentTab][0].nextElementSibling, "highlighted"); - removeClass(actives[currentTab][0], "highlighted"); - } - e.preventDefault(); - } else if (e.which === 13) { // return - if (actives[currentTab].length) { - var elem = actives[currentTab][0].getElementsByTagName("a")[0]; - document.location.href = elem.href; - } - } else if ([SHIFT, CTRL, ALT].indexOf(e.which) !== -1) { - // Does nothing, it's just to avoid losing "focus" on the highlighted element. - } else if (actives[currentTab].length > 0) { - removeClass(actives[currentTab][0], "highlighted"); - } - }; + // Focus the first search result on the active tab, or the result that + // was focused last time this tab was active. + function focusSearchResult() { + var target = searchState.focusedByTab[searchState.currentTab] || + document.querySelectorAll(".search-results.active a").item(0) || + document.querySelectorAll("#titles > button").item(searchState.currentTab); + if (target) { + target.focus(); + } } function buildHrefAndPath(item) { @@ -1047,45 +963,77 @@ window.initSearch = function(rawSearchIndex) { } function addTab(array, query, display) { - var extraStyle = ""; - if (display === false) { - extraStyle = " style=\"display: none;\""; + var extraClass = ""; + if (display === true) { + extraClass = " active"; } - var output = ""; + var output = document.createElement("div"); var duplicates = {}; var length = 0; if (array.length > 0) { - output = "<table class=\"search-results\"" + extraStyle + ">"; + output.className = "search-results " + extraClass; array.forEach(function(item) { - var name, type; - - name = item.name; - type = itemTypes[item.ty]; - if (item.is_alias !== true) { if (duplicates[item.fullPath]) { return; } duplicates[item.fullPath] = true; } + + var name = item.name; + var type = itemTypes[item.ty]; + length += 1; - output += "<tr class=\"" + type + " result\"><td>" + - "<a href=\"" + item.href + "\">" + - (item.is_alias === true ? - ("<span class=\"alias\"><b>" + item.alias + " </b></span><span " + - "class=\"grey\"><i> - see </i></span>") : "") + - item.displayPath + "<span class=\"" + type + "\">" + - name + "</span></a></td><td>" + - "<a href=\"" + item.href + "\">" + - "<span class=\"desc\">" + item.desc + - " </span></a></td></tr>"; + var extra = ""; + if (type === "primitive") { + extra = " <i>(primitive type)</i>"; + } else if (type === "keyword") { + extra = " <i>(keyword)</i>"; + } + + var link = document.createElement("a"); + link.className = "result-" + type; + link.href = item.href; + + var wrapper = document.createElement("div"); + var resultName = document.createElement("div"); + resultName.className = "result-name"; + + if (item.is_alias) { + var alias = document.createElement("span"); + alias.className = "alias"; + + var bold = document.createElement("b"); + bold.innerText = item.alias; + alias.appendChild(bold); + + alias.insertAdjacentHTML( + "beforeend", + "<span class=\"grey\"><i> - see </i></span>"); + + resultName.appendChild(alias); + } + resultName.insertAdjacentHTML( + "beforeend", + item.displayPath + "<span class=\"" + type + "\">" + name + extra + "</span>"); + wrapper.appendChild(resultName); + + var description = document.createElement("div"); + description.className = "desc"; + var spanDesc = document.createElement("span"); + spanDesc.innerText = item.desc + "\u00A0"; + + description.appendChild(spanDesc); + wrapper.appendChild(description); + link.appendChild(wrapper); + output.appendChild(link); }); - output += "</table>"; } else { - output = "<div class=\"search-failed\"" + extraStyle + ">No results :(<br/>" + + output.className = "search-failed" + extraClass; + output.innerHTML = "No results :(<br/>" + "Try on <a href=\"https://duckduckgo.com/?q=" + encodeURIComponent("rust " + query.query) + "\">DuckDuckGo</a>?<br/><br/>" + @@ -1097,7 +1045,7 @@ window.initSearch = function(rawSearchIndex) { "href=\"https://doc.rust-lang.org/book/index.html\">Rust Book</a> for " + "introductions to language features and the language itself.</li><li><a " + "href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" + - " <a href=\"https://crates.io/\">crates.io</a>.</li></ul></div>"; + " <a href=\"https://crates.io/\">crates.io</a>.</li></ul>"; } return [output, length]; } @@ -1121,7 +1069,7 @@ window.initSearch = function(rawSearchIndex) { { var elem = document.createElement("a"); elem.href = results.others[0].href; - elem.style.display = "none"; + removeClass(elem, "active"); // For firefox, we need the element to be in the DOM so it can be clicked. document.body.appendChild(elem); elem.click(); @@ -1157,12 +1105,19 @@ window.initSearch = function(rawSearchIndex) { makeTabHeader(0, "In Names", ret_others[1]) + makeTabHeader(1, "In Parameters", ret_in_args[1]) + makeTabHeader(2, "In Return Types", ret_returned[1]) + - "</div><div id=\"results\">" + - ret_others[0] + ret_in_args[0] + ret_returned[0] + "</div>"; + "</div>"; + + var resultsElem = document.createElement("div"); + resultsElem.id = "results"; + resultsElem.appendChild(ret_others[0]); + resultsElem.appendChild(ret_in_args[0]); + resultsElem.appendChild(ret_returned[0]); search.innerHTML = output; + search.appendChild(resultsElem); + // Reset focused elements. + searchState.focusedByTab = [null, null, null]; searchState.showResults(search); - initSearchNav(); var elems = document.getElementById("titles").childNodes; elems[0].onclick = function() { printTab(0); }; elems[1].onclick = function() { printTab(1); }; @@ -1440,6 +1395,49 @@ window.initSearch = function(rawSearchIndex) { }; searchState.input.onpaste = searchState.input.onchange; + searchState.outputElement().addEventListener("keydown", function(e) { + // We only handle unmodified keystrokes here. We don't want to interfere with, + // for instance, alt-left and alt-right for history navigation. + if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) { + return; + } + // up and down arrow select next/previous search result, or the + // search box if we're already at the top. + if (e.which === 38) { // up + var previous = document.activeElement.previousElementSibling; + if (previous) { + previous.focus(); + } else { + searchState.focus(); + } + e.preventDefault(); + } else if (e.which === 40) { // down + var next = document.activeElement.nextElementSibling; + if (next) { + next.focus(); + } + var rect = document.activeElement.getBoundingClientRect(); + if (window.innerHeight - rect.bottom < rect.height) { + window.scrollBy(0, rect.height); + } + e.preventDefault(); + } else if (e.which === 37) { // left + nextTab(-1); + e.preventDefault(); + } else if (e.which === 39) { // right + nextTab(1); + e.preventDefault(); + } + }); + + searchState.input.addEventListener("keydown", function(e) { + if (e.which === 40) { // down + focusSearchResult(); + e.preventDefault(); + } + }); + + var selectCrate = document.getElementById("crate-search"); if (selectCrate) { selectCrate.onchange = function() { diff --git a/src/librustdoc/html/static/sidebar-items.js b/src/librustdoc/html/static/sidebar-items.js deleted file mode 100644 index 81172ba0d92..00000000000 --- a/src/librustdoc/html/static/sidebar-items.js +++ /dev/null @@ -1 +0,0 @@ -initSidebarItems({}); diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index 16f40ec14d5..d220d8708a1 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -10,8 +10,7 @@ body { color: #c5c5c5; } -h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), -h4:not(.method):not(.type):not(.tymethod) { +h1, h2, h3, h4 { color: white; } h1.fqn { @@ -20,10 +19,10 @@ h1.fqn { h1.fqn a { color: #fff; } -h2, h3:not(.impl):not(.method):not(.type):not(.tymethod) { +h2, h3, h4 { border-bottom-color: #5c6773; } -h4:not(.method):not(.type):not(.tymethod):not(.associatedconstant) { +h4 { border: none; } @@ -151,12 +150,12 @@ pre, .rustdoc.source .example-wrap { color: #c5c5c5; } -.content .highlighted { - color: #000 !important; - background-color: #c6afb3; +.search-results a:hover { + background-color: #777; } -.content .highlighted a, .content .highlighted span { color: #000 !important; } -.content .highlighted { + +.search-results a:focus { + color: #000 !important; background-color: #c6afb3; } .search-results a { @@ -407,6 +406,10 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: #5c6773; } +.notable-traits-tooltiptext .notable { + border-bottom-color: #5c6773; +} + #titles > button.selected { background-color: #141920 !important; border-bottom: 1px solid #ffb44c !important; @@ -432,31 +435,21 @@ individually rather than as a group) */ /* FIXME: these rules should be at the bottom of the file but currently must be above the `@media (max-width: 700px)` rules due to a bug in the css checker */ /* see https://github.com/rust-lang/rust/pull/71237#issuecomment-618170143 */ -.content .highlighted.mod, .content .highlighted.externcrate {} .search-input:focus {} .content span.attr,.content a.attr,.block a.current.attr,.content span.derive,.content a.derive, .block a.current.derive,.content span.macro,.content a.macro,.block a.current.macro {} -.content .highlighted.trait {} .content span.struct,.content a.struct,.block a.current.struct {} #titles>button:hover,#titles>button.selected {} -.content .highlighted.traitalias {} .content span.type,.content a.type,.block a.current.type {} .content span.union,.content a.union,.block a.current.union {} -.content .highlighted.foreigntype {} pre.rust .lifetime {} -.content .highlighted.primitive {} -.content .highlighted.constant,.content .highlighted.static {} .stab.unstable {} -.content .highlighted.fn,.content .highlighted.method,.content .highlighted.tymethod {} h2,h3:not(.impl):not(.method):not(.type):not(.tymethod),h4:not(.method):not(.type):not(.tymethod) {} .content span.enum,.content a.enum,.block a.current.enum {} .content span.constant,.content a.constant,.block a.current.constant,.content span.static, -.content a.static,.block a.current.static {} +.content a.static, .block a.current.static {} .content span.keyword,.content a.keyword,.block a.current.keyword {} pre.rust .comment {} -.content .highlighted.enum {} -.content .highlighted.struct {} -.content .highlighted.keyword {} .content span.traitalias,.content a.traitalias,.block a.current.traitalias {} .content span.fn,.content a.fn,.block a.current.fn,.content span.method,.content a.method, .block a.current.method,.content span.tymethod,.content a.tymethod,.block a.current.tymethod, @@ -467,15 +460,36 @@ pre.rust .attribute .ident {} .content span.foreigntype,.content a.foreigntype,.block a.current.foreigntype {} pre.rust .doccomment {} .stab.deprecated {} -.content .highlighted.attr,.content .highlighted.derive,.content .highlighted.macro {} +.content a.attr,.content a.derive,.content a.macro {} .stab.portability {} -.content .highlighted.union {} .content span.primitive,.content a.primitive,.block a.current.primitive {} .content span.externcrate,.content span.mod,.content a.mod,.block a.current.mod {} -.content .highlighted.type {} pre.rust .kw-2,pre.rust .prelude-ty {} .content span.trait,.content a.trait,.block a.current.trait {} +.search-results a:focus span {} +a.result-trait:focus {} +a.result-traitalias:focus {} +a.result-mod:focus, +a.result-externcrate:focus {} +a.result-mod:focus {} +a.result-externcrate:focus {} +a.result-enum:focus {} +a.result-struct:focus {} +a.result-union:focus {} +a.result-fn:focus, +a.result-method:focus, +a.result-tymethod:focus {} +a.result-type:focus {} +a.result-foreigntype:focus {} +a.result-attr:focus, +a.result-derive:focus, +a.result-macro:focus {} +a.result-constant:focus, +a.result-static:focus {} +a.result-primitive:focus {} +a.result-keyword:focus {} + @media (max-width: 700px) { .sidebar-menu { background-color: #14191f; @@ -502,20 +516,29 @@ kbd { box-shadow-color: #c6cbd1; } -#theme-picker, #settings-menu, #help-button, #copy-path { +#theme-picker, #settings-menu, #help-button { border-color: #5c6773; background-color: #0f1419; color: #fff; } -#theme-picker > img, #settings-menu > img, #copy-path > img { +#theme-picker > img, #settings-menu > img { filter: invert(100); } +#copy-path { + color: #fff; +} +#copy-path > img { + filter: invert(70%); +} +#copy-path:hover > img { + filter: invert(100%); +} + #theme-picker:hover, #theme-picker:focus, #settings-menu:hover, #settings-menu:focus, -#help-button:hover, #help-button:focus, -#copy-path:hover, #copy-path:focus { +#help-button:hover, #help-button:focus { border-color: #e0e0e0; } @@ -545,10 +568,10 @@ kbd { background-color: rgba(70, 70, 70, 0.33); } -.search-results td span.alias { +.search-results .result-name span.alias { color: #c5c5c5; } -.search-results td span.grey { +.search-results .result-name span.grey { color: #999; } diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index fe05a462e81..6385a763f2e 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -3,15 +3,13 @@ body { color: #ddd; } -h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), -h4:not(.method):not(.type):not(.tymethod) { +h1, h2, h3, h4 { color: #ddd; } h1.fqn { border-bottom-color: #d2d2d2; } -h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), -h4:not(.method):not(.type):not(.tymethod) { +h2, h3, h4 { border-bottom-color: #d2d2d2; } @@ -109,32 +107,36 @@ pre, .rustdoc.source .example-wrap { color: #ddd; } -.content .highlighted { +.search-results a:hover { + background-color: #777; +} + +.search-results a:focus { color: #eee !important; background-color: #616161; } -.content .highlighted a, .content .highlighted span { color: #eee !important; } -.content .highlighted.trait { background-color: #013191; } -.content .highlighted.traitalias { background-color: #013191; } -.content .highlighted.mod, -.content .highlighted.externcrate { background-color: #afc6e4; } -.content .highlighted.mod { background-color: #803a1b; } -.content .highlighted.externcrate { background-color: #396bac; } -.content .highlighted.enum { background-color: #5b4e68; } -.content .highlighted.struct { background-color: #194e9f; } -.content .highlighted.union { background-color: #b7bd49; } -.content .highlighted.fn, -.content .highlighted.method, -.content .highlighted.tymethod { background-color: #4950ed; } -.content .highlighted.type { background-color: #38902c; } -.content .highlighted.foreigntype { background-color: #b200d6; } -.content .highlighted.attr, -.content .highlighted.derive, -.content .highlighted.macro { background-color: #217d1c; } -.content .highlighted.constant, -.content .highlighted.static { background-color: #0063cc; } -.content .highlighted.primitive { background-color: #00708a; } -.content .highlighted.keyword { background-color: #884719; } +.search-results a:focus span { color: #eee !important; } +a.result-trait:focus { background-color: #013191; } +a.result-traitalias:focus { background-color: #013191; } +a.result-mod:focus, +a.result-externcrate:focus { background-color: #afc6e4; } +a.result-mod:focus { background-color: #803a1b; } +a.result-externcrate:focus { background-color: #396bac; } +a.result-enum:focus { background-color: #5b4e68; } +a.result-struct:focus { background-color: #194e9f; } +a.result-union:focus { background-color: #b7bd49; } +a.result-fn:focus, +a.result-method:focus, +a.result-tymethod:focus { background-color: #4950ed; } +a.result-type:focus { background-color: #38902c; } +a.result-foreigntype:focus { background-color: #b200d6; } +a.result-attr:focus, +a.result-derive:focus, +a.result-macro:focus { background-color: #217d1c; } +a.result-constant:focus, +a.result-static:focus { background-color: #0063cc; } +a.result-primitive:focus { background-color: #00708a; } +a.result-keyword:focus { background-color: #884719; } .content .item-info::before { color: #ccc; } @@ -352,6 +354,10 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: #777; } +.notable-traits-tooltiptext .notable { + border-bottom-color: #d2d2d2; +} + #titles > button:not(.selected) { background-color: #252525; border-top-color: #252525; @@ -392,7 +398,7 @@ kbd { box-shadow-color: #c6cbd1; } -#theme-picker, #settings-menu, #help-button, #copy-path { +#theme-picker, #settings-menu, #help-button { border-color: #e0e0e0; background: #f0f0f0; color: #000; @@ -400,11 +406,20 @@ kbd { #theme-picker:hover, #theme-picker:focus, #settings-menu:hover, #settings-menu:focus, -#help-button:hover, #help-button:focus, -#copy-path:hover, #copy-path:focus { +#help-button:hover, #help-button:focus { border-color: #ffb900; } +#copy-path { + color: #999; +} +#copy-path > img { + filter: invert(50%); +} +#copy-path:hover > img { + filter: invert(65%); +} + #theme-choices { border-color: #e0e0e0; background-color: #353535; @@ -431,10 +446,10 @@ kbd { background-color: #606060; } -.search-results td span.alias { +.search-results .result-name span.alias { color: #fff; } -.search-results td span.grey { +.search-results .result-name span.grey { color: #ccc; } diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 2253fac1c09..c19d5bfc317 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -5,15 +5,13 @@ body { color: black; } -h1, h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), -h4:not(.method):not(.type):not(.tymethod) { +h1, h2, h3, h4 { color: black; } h1.fqn { border-bottom-color: #D5D5D5; } -h2, h3:not(.impl):not(.method):not(.type):not(.tymethod), -h4:not(.method):not(.type):not(.tymethod) { +h2, h3, h4 { border-bottom-color: #DDDDDD; } @@ -109,30 +107,34 @@ pre, .rustdoc.source .example-wrap { color: #4E4C4C; } -.content .highlighted { +.search-results a:hover { + background-color: #ddd; +} + +.search-results a:focus { color: #000 !important; background-color: #ccc; } -.content .highlighted a, .content .highlighted span { color: #000 !important; } -.content .highlighted.trait { background-color: #c7b6ff; } -.content .highlighted.traitalias { background-color: #c7b6ff; } -.content .highlighted.mod, -.content .highlighted.externcrate { background-color: #afc6e4; } -.content .highlighted.enum { background-color: #b4d1b9; } -.content .highlighted.struct { background-color: #e7b1a0; } -.content .highlighted.union { background-color: #b7bd49; } -.content .highlighted.fn, -.content .highlighted.method, -.content .highlighted.tymethod { background-color: #c6afb3; } -.content .highlighted.type { background-color: #ffc891; } -.content .highlighted.foreigntype { background-color: #f5c4ff; } -.content .highlighted.attr, -.content .highlighted.derive, -.content .highlighted.macro { background-color: #8ce488; } -.content .highlighted.constant, -.content .highlighted.static { background-color: #c3e0ff; } -.content .highlighted.primitive { background-color: #9aecff; } -.content .highlighted.keyword { background-color: #f99650; } +.search-results a:focus span { color: #000 !important; } +a.result-trait:focus { background-color: #c7b6ff; } +a.result-traitalias:focus { background-color: #c7b6ff; } +a.result-mod:focus, +a.result-externcrate:focus { background-color: #afc6e4; } +a.result-enum:focus { background-color: #b4d1b9; } +a.result-struct:focus { background-color: #e7b1a0; } +a.result-union:focus { background-color: #b7bd49; } +a.result-fn:focus, +a.result-method:focus, +a.result-tymethod:focus { background-color: #c6afb3; } +a.result-type:focus { background-color: #ffc891; } +a.result-foreigntype:focus { background-color: #f5c4ff; } +a.result-attr:focus, +a.result-derive:focus, +a.result-macro:focus { background-color: #8ce488; } +a.result-constant:focus, +a.result-static:focus { background-color: #c3e0ff; } +a.result-primitive:focus { background-color: #9aecff; } +a.result-keyword:focus { background-color: #f99650; } .content .item-info::before { color: #ccc; } @@ -344,6 +346,10 @@ pre.ignore:hover, .information:hover + pre.ignore { border-color: #999; } +.notable-traits-tooltiptext .notable { + border-bottom-color: #DDDDDD; +} + #titles > button:not(.selected) { background-color: #e6e6e6; border-top-color: #e6e6e6; @@ -384,18 +390,27 @@ kbd { box-shadow-color: #c6cbd1; } -#theme-picker, #settings-menu, #help-button, #copy-path { +#theme-picker, #settings-menu, #help-button { border-color: #e0e0e0; background-color: #fff; } #theme-picker:hover, #theme-picker:focus, #settings-menu:hover, #settings-menu:focus, -#help-button:hover, #help-button:focus, -#copy-path:hover, #copy-path:focus { +#help-button:hover, #help-button:focus { border-color: #717171; } +#copy-path { + color: #999; +} +#copy-path > img { + filter: invert(50%); +} +#copy-path:hover > img { + filter: invert(35%); +} + #theme-choices { border-color: #ccc; background-color: #fff; @@ -422,10 +437,10 @@ kbd { background-color: #f9f9f9; } -.search-results td span.alias { +.search-results .result-name span.alias { color: #000; } -.search-results td span.grey { +.search-results .result-name span.grey { color: #999; } diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 4e3d5ff0a4a..ca7e5ef8150 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -126,11 +126,19 @@ crate mod source_code_pro { crate static LICENSE: &[u8] = include_bytes!("static/SourceCodePro-LICENSE.txt"); } +crate mod noto_sans_kr { + /// The file `noto-sans-kr-v13-korean-regular.woff`, the Regular variant of the Noto Sans KR + /// font. + crate static REGULAR: &[u8] = include_bytes!("static/noto-sans-kr-v13-korean-regular.woff"); + + /// The file `noto-sans-kr-v13-korean-regular-LICENSE.txt`, the license text of the Noto Sans KR + /// font. + crate static LICENSE: &[u8] = + include_bytes!("static/noto-sans-kr-v13-korean-regular-LICENSE.txt"); +} + /// Files related to the sidebar in rustdoc sources. crate mod sidebar { /// File script to handle sidebar. crate static SOURCE_SCRIPT: &str = include_str!("static/source-script.js"); - - /// Top Level sidebar items script which will load a sidebar without items. - crate static ITEMS: &str = include_str!("static/sidebar-items.js"); } diff --git a/src/librustdoc/json/conversions.rs b/src/librustdoc/json/conversions.rs index e0c0e241497..bee62915ea9 100644 --- a/src/librustdoc/json/conversions.rs +++ b/src/librustdoc/json/conversions.rs @@ -396,7 +396,7 @@ impl FromWithTcx<clean::Type> for Type { mutable: mutability == ast::Mutability::Mut, type_: Box::new((*type_).into_tcx(tcx)), }, - QPath { name, self_type, trait_ } => Type::QualifiedPath { + QPath { name, self_type, trait_, .. } => Type::QualifiedPath { name: name.to_string(), self_type: Box::new((*self_type).into_tcx(tcx)), trait_: Box::new((*trait_).into_tcx(tcx)), diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 5ede3780e87..7c93a094807 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -8,7 +8,6 @@ #![feature(box_syntax)] #![feature(in_band_lifetimes)] #![feature(nll)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(test)] #![feature(crate_visibility_modifier)] #![feature(never_type)] @@ -511,6 +510,14 @@ fn opts() -> Vec<RustcOptGroup> { "LEVEL", ) }), + unstable("force-warns", |o| { + o.optopt( + "", + "force-warns", + "Lints that will warn even if allowed somewhere else", + "LINTS", + ) + }), unstable("index-page", |o| { o.optopt("", "index-page", "Markdown file to be used as index page", "PATH") }), @@ -582,9 +589,6 @@ fn opts() -> Vec<RustcOptGroup> { "Generate JSON file at the top level instead of generating HTML redirection files", ) }), - unstable("print", |o| { - o.optmulti("", "print", "Rustdoc information to print on stdout", "[unversioned-files]") - }), unstable("emit", |o| { o.optmulti( "", diff --git a/src/librustdoc/lint.rs b/src/librustdoc/lint.rs index 1b79811d4b0..376c83b1a6e 100644 --- a/src/librustdoc/lint.rs +++ b/src/librustdoc/lint.rs @@ -157,6 +157,18 @@ declare_rustdoc_lint! { "detects URLs that are not hyperlinks" } +declare_rustdoc_lint! { + /// The `invalid_rust_codeblocks` lint detects Rust code blocks in + /// documentation examples that are invalid (e.g. empty, not parsable as + /// Rust code). This is a `rustdoc` only lint, see the documentation in the + /// [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_rust_codeblocks + INVALID_RUST_CODEBLOCKS, + Warn, + "codeblock could not be parsed as valid Rust or is empty" +} + crate static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| { vec![ BROKEN_INTRA_DOC_LINKS, @@ -164,6 +176,7 @@ crate static RUSTDOC_LINTS: Lazy<Vec<&'static Lint>> = Lazy::new(|| { MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS, INVALID_CODEBLOCK_ATTRIBUTES, + INVALID_RUST_CODEBLOCKS, INVALID_HTML_TAGS, BARE_URLS, MISSING_CRATE_LEVEL_DOCS, diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index 8d07cde5188..7ccfdf29041 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -1,5 +1,6 @@ use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler}; +use rustc_middle::lint::LintDiagnosticBuilder; use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; @@ -47,55 +48,68 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { .unwrap_or(false); let buffer = buffer.borrow(); - if buffer.has_errors || is_empty { - let mut diag = if let Some(sp) = super::source_span_for_markdown_range( - self.cx.tcx, - &dox, - &code_block.range, - &item.attrs, - ) { - let (warning_message, suggest_using_text) = if buffer.has_errors { - ("could not parse code block as Rust code", true) - } else { - ("Rust code block is empty", false) - }; - - let mut diag = self.cx.sess().struct_span_warn(sp, warning_message); - - if code_block.syntax.is_none() && code_block.is_fenced { - let sp = sp.from_inner(InnerSpan::new(0, 3)); - diag.span_suggestion( - sp, - "mark blocks that do not contain Rust code as text", - String::from("```text"), - Applicability::MachineApplicable, + if !buffer.has_errors && !is_empty { + // No errors in a non-empty program. + return; + } + + let local_id = match item.def_id.as_real().and_then(|x| x.as_local()) { + Some(id) => id, + // We don't need to check the syntax for other crates so returning + // without doing anything should not be a problem. + None => return, + }; + + let hir_id = self.cx.tcx.hir().local_def_id_to_hir_id(local_id); + let empty_block = code_block.syntax.is_none() && code_block.is_fenced; + let is_ignore = code_block.is_ignore; + + // The span and whether it is precise or not. + let (sp, precise_span) = match super::source_span_for_markdown_range( + self.cx.tcx, + &dox, + &code_block.range, + &item.attrs, + ) { + Some(sp) => (sp, true), + None => (item.attr_span(self.cx.tcx), false), + }; + + // lambda that will use the lint to start a new diagnostic and add + // a suggestion to it when needed. + let diag_builder = |lint: LintDiagnosticBuilder<'_>| { + let explanation = if is_ignore { + "`ignore` code blocks require valid Rust code for syntax highlighting; \ + mark blocks that do not contain Rust code as text" + } else { + "mark blocks that do not contain Rust code as text" + }; + let msg = if buffer.has_errors { + "could not parse code block as Rust code" + } else { + "Rust code block is empty" + }; + let mut diag = lint.build(msg); + + if precise_span { + if is_ignore { + // giving an accurate suggestion is hard because `ignore` might not have come first in the list. + // just give a `help` instead. + diag.span_help( + sp.from_inner(InnerSpan::new(0, 3)), + &format!("{}: ```text", explanation), ); - } else if suggest_using_text && code_block.is_ignore { - let sp = sp.from_inner(InnerSpan::new(0, 3)); + } else if empty_block { diag.span_suggestion( - sp, - "`ignore` code blocks require valid Rust code for syntax highlighting. \ - Mark blocks that do not contain Rust code as text", - String::from("```text,"), + sp.from_inner(InnerSpan::new(0, 3)), + explanation, + String::from("```text"), Applicability::MachineApplicable, ); } - - diag - } else { - // We couldn't calculate the span of the markdown block that had the error, so our - // diagnostics are going to be a bit lacking. - let mut diag = self.cx.sess().struct_span_warn( - item.attr_span(self.cx.tcx), - "doc comment contains an invalid Rust code block", - ); - - if code_block.syntax.is_none() && code_block.is_fenced { - diag.help("mark blocks that do not contain Rust code as text: ```text"); - } - - diag - }; + } else if empty_block || is_ignore { + diag.help(&format!("{}: ```text", explanation)); + } // FIXME(#67563): Provide more context for these errors by displaying the spans inline. for message in buffer.messages.iter() { @@ -103,7 +117,17 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { } diag.emit(); - } + }; + + // Finally build and emit the completed diagnostic. + // All points of divergence have been handled earlier so this can be + // done the same way whether the span is precise or not. + self.cx.tcx.struct_span_lint_hir( + crate::lint::INVALID_RUST_CODEBLOCKS, + hir_id, + sp, + diag_builder, + ); } } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index 191d8d5a2ea..b563c4f4799 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -9,6 +9,7 @@ use rustc_hir::Node; use rustc_middle::middle::privacy::AccessLevel; use rustc_middle::ty::TyCtxt; use rustc_span; +use rustc_span::def_id::LOCAL_CRATE; use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Symbol}; @@ -76,7 +77,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { &Spanned { span, node: hir::VisibilityKind::Public }, hir::CRATE_HIR_ID, &krate.item, - self.cx.tcx.crate_name, + self.cx.tcx.crate_name(LOCAL_CRATE), ); // Attach the crate's exported macros to the top-level module. // In the case of macros 2.0 (`pub macro`), and for built-in `derive`s or attributes as diff --git a/src/stage0.txt b/src/stage0.txt index 6ad0f6db42b..1027057f385 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,7 +12,7 @@ # stable release's version number. `date` is the date where the release we're # bootstrapping off was released. -date: 2021-04-07 +date: 2021-05-23 rustc: beta # We use a nightly rustfmt to format the source because it solves some diff --git a/src/test/assembly/static-relocation-model.rs b/src/test/assembly/static-relocation-model.rs index 0463045c156..2cd74a01c84 100644 --- a/src/test/assembly/static-relocation-model.rs +++ b/src/test/assembly/static-relocation-model.rs @@ -1,9 +1,10 @@ // min-llvm-version: 12.0.0 -// needs-llvm-components: aarch64 x86 -// revisions:X64 A64 +// needs-llvm-components: aarch64 x86 powerpc +// revisions: x64 A64 ppc64le // assembly-output: emit-asm -// [X64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static +// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static // [A64] compile-flags: --target aarch64-unknown-linux-gnu -Crelocation-model=static +// [ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -Crelocation-model=static #![feature(no_core, lang_items)] #![no_core] @@ -15,14 +16,26 @@ trait Sized {} #[lang="copy"] trait Copy {} +#[lang="sync"] +trait Sync {} + +#[lang = "drop_in_place"] +fn drop_in_place<T>(_: *mut T) {} + impl Copy for u8 {} +impl Sync for u8 {} + +#[no_mangle] +pub static PIERIS: u8 = 42; extern "C" { + static EXOCHORDA: *mut u8; + fn chaenomeles(); } // CHECK-LABEL: banana: -// x64: movb chaenomeles, %{{[a,z]+}} +// x64: movb chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} // A64: adrp [[REG:[a-z0-9]+]], chaenomeles // A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG]], :lo12:chaenomeles] #[no_mangle] @@ -33,7 +46,7 @@ pub fn banana() -> u8 { } // CHECK-LABEL: peach: -// x64: movb banana, %{{[a,z]+}} +// x64: movb banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} // A64: adrp [[REG2:[a-z0-9]+]], banana // A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:banana] #[no_mangle] @@ -42,3 +55,30 @@ pub fn peach() -> u8 { *(banana as *mut u8) } } + +// CHECK-LABEL: mango: +// x64: movq EXOCHORDA{{(\(%[a-z0-9]+\))?}}, %[[REG:[a-z0-9]+]] +// x64-NEXT: movb (%[[REG]]), %{{[a-z0-9]+}} +// A64: adrp [[REG2:[a-z0-9]+]], EXOCHORDA +// A64-NEXT: ldr {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:EXOCHORDA] +#[no_mangle] +pub fn mango() -> u8 { + unsafe { + *EXOCHORDA + } +} + +// CHECK-LABEL: orange: +// x64: mov{{l|absq}} $PIERIS, %{{[a-z0-9]+}} +// A64: adrp [[REG2:[a-z0-9]+]], PIERIS +// A64-NEXT: add {{[a-z0-9]+}}, [[REG2]], :lo12:PIERIS +#[no_mangle] +pub fn orange() -> &'static u8 { + &PIERIS +} + +// For ppc64 we need to make sure to generate TOC entries even with the static relocation model +// ppc64le: .tc chaenomeles[TC],chaenomeles +// ppc64le: .tc banana[TC],banana +// ppc64le: .tc EXOCHORDA[TC],EXOCHORDA +// ppc64le: .tc PIERIS[TC],PIERIS diff --git a/src/test/codegen/async-fn-debug-msvc.rs b/src/test/codegen/async-fn-debug-msvc.rs index f2641404aae..e410180bfff 100644 --- a/src/test/codegen/async-fn-debug-msvc.rs +++ b/src/test/codegen/async-fn-debug-msvc.rs @@ -17,33 +17,33 @@ async fn async_fn_test() { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[ASYNC_FN:!.*]] = !DINamespace(name: "async_fn_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[ASYNC_FN]] -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0" +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], // For brevity, we only check the struct name and members of the last variant. // CHECK-SAME: file: [[FILE:![0-9]*]], line: 11, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 15, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 15, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 12, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 14, // CHECK-SAME: baseType: [[VARIANT:![0-9]*]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[ASYNC_FN]], +// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]], // CHECK-SAME: flags: DIFlagArtificial // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] // CHECK-NOT: flags: DIFlagArtificial diff --git a/src/test/codegen/auxiliary/thread_local_aux.rs b/src/test/codegen/auxiliary/thread_local_aux.rs new file mode 100644 index 00000000000..29b5e3ca244 --- /dev/null +++ b/src/test/codegen/auxiliary/thread_local_aux.rs @@ -0,0 +1,6 @@ +#![crate_type = "lib"] +#![feature(thread_local_const_init)] + +use std::cell::Cell; + +thread_local!(pub static A: Cell<u64> = const { Cell::new(0) }); diff --git a/src/test/codegen/generator-debug-msvc.rs b/src/test/codegen/generator-debug-msvc.rs index 44be71f3b9b..7edb07d224c 100644 --- a/src/test/codegen/generator-debug-msvc.rs +++ b/src/test/codegen/generator-debug-msvc.rs @@ -21,33 +21,33 @@ fn generator_test() -> impl Generator<Yield = i32, Return = ()> { // FIXME: No way to reliably check the filename. // CHECK-DAG: [[GEN_FN:!.*]] = !DINamespace(name: "generator_test" -// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0", scope: [[GEN_FN]] -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK-DAG: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "generator-0" +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant0", scope: [[GEN]], // For brevity, we only check the struct name and members of the last variant. // CHECK-SAME: file: [[FILE:![0-9]*]], line: 14, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant1", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 18, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant2", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 18, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant3", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 15, // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, scope: [[GEN]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant4", scope: [[GEN]], // CHECK-SAME: file: [[FILE]], line: 17, // CHECK-SAME: baseType: [[VARIANT:![0-9]*]] // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN_FN]], +// CHECK: [[S1:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend1", scope: [[GEN]], // CHECK-NOT: flags: DIFlagArtificial // CHECK-SAME: ) -// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "RUST$ENUM$DISR", scope: [[S1]], +// CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "variant$", scope: [[S1]], // CHECK-SAME: flags: DIFlagArtificial // CHECK: {{!.*}} = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: [[S1]] // CHECK-NOT: flags: DIFlagArtificial diff --git a/src/test/codegen/thread-local.rs b/src/test/codegen/thread-local.rs new file mode 100644 index 00000000000..f14368e3990 --- /dev/null +++ b/src/test/codegen/thread-local.rs @@ -0,0 +1,50 @@ +// compile-flags: -O +// aux-build:thread_local_aux.rs +// ignore-windows FIXME(#84933) +// ignore-wasm globals are used instead of thread locals +// ignore-emscripten globals are used instead of thread locals +// ignore-android does not use #[thread_local] + +#![crate_type = "lib"] +#![feature(thread_local_const_init)] + +extern crate thread_local_aux as aux; + +use std::cell::Cell; + +thread_local!(static A: Cell<u32> = const { Cell::new(1) }); + +// CHECK: [[TLS_AUX:@.+]] = external thread_local local_unnamed_addr global i64 +// CHECK: [[TLS:@.+]] = internal thread_local unnamed_addr global + +// CHECK-LABEL: @get +#[no_mangle] +fn get() -> u32 { + // CHECK: %0 = load i32, i32* bitcast ({{.*}} [[TLS]] to i32*) + // CHECK-NEXT: ret i32 %0 + A.with(|a| a.get()) +} + +// CHECK-LABEL: @set +#[no_mangle] +fn set(v: u32) { + // CHECK: store i32 %0, i32* bitcast ({{.*}} [[TLS]] to i32*) + // CHECK-NEXT: ret void + A.with(|a| a.set(v)) +} + +// CHECK-LABEL: @get_aux +#[no_mangle] +fn get_aux() -> u64 { + // CHECK: %0 = load i64, i64* [[TLS_AUX]] + // CHECK-NEXT: ret i64 %0 + aux::A.with(|a| a.get()) +} + +// CHECK-LABEL: @set_aux +#[no_mangle] +fn set_aux(v: u64) { + // CHECK: store i64 %0, i64* [[TLS_AUX]] + // CHECK-NEXT: ret void + aux::A.with(|a| a.set(v)) +} diff --git a/src/test/codegen/try_identity.rs b/src/test/codegen/try_identity.rs index 81e2435e5b8..3ff77163b9f 100644 --- a/src/test/codegen/try_identity.rs +++ b/src/test/codegen/try_identity.rs @@ -7,11 +7,28 @@ type R = Result<u64, i32>; +// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure, +// so the relevant desugar is copied inline in order to keep the test testing the same thing. +// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR +// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not. #[no_mangle] -fn try_identity(x: R) -> R { +pub fn try_identity(x: R) -> R { // CHECK: start: // CHECK-NOT: br {{.*}} // CHECK ret void - let y = x?; + let y = match into_result(x) { + Err(e) => return from_error(From::from(e)), + Ok(v) => v, + }; Ok(y) } + +#[inline] +fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> { + r +} + +#[inline] +fn from_error<T, E>(e: E) -> Result<T, E> { + Err(e) +} diff --git a/src/test/debuginfo/msvc-pretty-enums.rs b/src/test/debuginfo/msvc-pretty-enums.rs new file mode 100644 index 00000000000..550cc66f389 --- /dev/null +++ b/src/test/debuginfo/msvc-pretty-enums.rs @@ -0,0 +1,97 @@ +// only-cdb +// ignore-tidy-linelength +// compile-flags:-g + +// cdb-command: g + +// Note: The natvis used to visualize niche-layout enums don't work correctly in cdb +// so the best we can do is to make sure we are generating the right debuginfo + +// cdb-command: dx -r2 a,! +// cdb-check:a,! [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Some] +// cdb-check: [+0x000] __0 : Low (0x2) [Type: msvc_pretty_enums::CStyleEnum] +// cdb-check: [+0x000] discriminant : 0x2 [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Discriminant$] + +// cdb-command: dx -r2 b,! +// cdb-check:b,! [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Some] +// cdb-check: [+0x000] __0 : 0x11 [Type: msvc_pretty_enums::CStyleEnum] +// cdb-check: [+0x000] discriminant : None (0x11) [Type: enum$<core::option::Option<enum$<msvc_pretty_enums::CStyleEnum>>, 2, 16, Some>::Discriminant$] + +// cdb-command: dx -r2 c,! +// cdb-check:c,! [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>] +// cdb-check: [+0x000] dataful_variant [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data] +// cdb-check: [+0x000] my_data : 0x11 [Type: msvc_pretty_enums::CStyleEnum] +// cdb-check: [+0x000] discriminant : Tag1 (0x11) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$] + +// cdb-command: dx -r2 d,! +// cdb-check:d,! [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>] +// cdb-check: [+0x000] dataful_variant [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data] +// cdb-check: [+0x000] my_data : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] +// cdb-check: [+0x000] discriminant : 0x10 [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$] + +// cdb-command: dx -r2 e,! +// cdb-check:e,! [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>] +// cdb-check: [+0x000] dataful_variant [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Data] +// cdb-check: [+0x000] my_data : 0x13 [Type: msvc_pretty_enums::CStyleEnum] +// cdb-check: [+0x000] discriminant : Tag2 (0x13) [Type: enum$<msvc_pretty_enums::NicheLayoutEnum, 2, 16, Data>::Discriminant$] + +// cdb-command: dx -r2 f,! +// cdb-check:f,! [Type: enum$<core::option::Option<u32*>, 1, [...], Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Some] +// cdb-check: [+0x000] __0 : 0x[...] : 0x1 [Type: unsigned int *] +// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Discriminant$] + +// cdb-command: dx -r2 g,! +// cdb-check:g,! [Type: enum$<core::option::Option<u32*>, 1, [...], Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Some] +// cdb-check: [+0x000] __0 : 0x0 [Type: unsigned int *] +// cdb-check: [+0x000] discriminant : None (0x0) [Type: enum$<core::option::Option<u32*>, 1, [...], Some>::Discriminant$] + +// cdb-command: dx h +// cdb-check:h : Some [Type: enum$<core::option::Option<u32>>] +// cdb-check: [+0x000] variant$ : Some (0x1) [Type: core::option::Option] +// cdb-check: [+0x004] __0 : 0xc [Type: unsigned int] + +// cdb-command: dx i +// cdb-check:i : None [Type: enum$<core::option::Option<u32>>] +// cdb-check: [+0x000] variant$ : None (0x0) [Type: core::option::Option] + +// cdb-command: dx j +// cdb-check:j : High (0x10) [Type: msvc_pretty_enums::CStyleEnum] + +// cdb-command: dx -r2 k,! +// cdb-check:k,! [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>] +// cdb-check: [+0x000] dataful_variant [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Some] +// cdb-check: [+0x000] __0 [Type: alloc::string::String] +// cdb-check: [+0x000] discriminant : 0x[...] [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>::Discriminant$] + +pub enum CStyleEnum { + Low = 2, + High = 16, +} + +pub enum NicheLayoutEnum { + Tag1, + Data { my_data: CStyleEnum }, + Tag2, +} + +fn main() { + let a = Some(CStyleEnum::Low); + let b = Option::<CStyleEnum>::None; + let c = NicheLayoutEnum::Tag1; + let d = NicheLayoutEnum::Data { my_data: CStyleEnum::High }; + let e = NicheLayoutEnum::Tag2; + let f = Some(&1u32); + let g = Option::<&'static u32>::None; + let h = Some(12u32); + let i = Option::<u32>::None; + let j = CStyleEnum::High; + let k = Some("IAMA optional string!".to_string()); + + zzz(); // #break +} + +fn zzz() { () } diff --git a/src/test/debuginfo/pretty-std.rs b/src/test/debuginfo/pretty-std.rs index 1a99f841250..68e73b5f38d 100644 --- a/src/test/debuginfo/pretty-std.rs +++ b/src/test/debuginfo/pretty-std.rs @@ -1,6 +1,7 @@ // ignore-freebsd: gdb package too new // only-cdb // "Temporarily" ignored on GDB/LLDB due to debuginfo tests being disabled, see PR 47155 // ignore-android: FIXME(#10381) +// ignore-tidy-linelength // compile-flags:-g // min-gdb-version: 7.7 // min-lldb-version: 310 @@ -111,11 +112,11 @@ // NOTE: OsString doesn't have a .natvis entry yet. // cdb-command: dx some -// cdb-check:some : Some(8) [Type: [...]::Option<i16>] +// cdb-check:some : Some [Type: enum$<core::option::Option<i16>>] // cdb-command: dx none -// cdb-check:none : None [Type: [...]::Option<i64>] +// cdb-check:none : None [Type: enum$<core::option::Option<i64>>] // cdb-command: dx some_string -// cdb-check:some_string : Some("IAMA optional string!") [[...]::Option<[...]::String>] +// cdb-check:some_string [Type: enum$<core::option::Option<alloc::string::String>, 1, [...], Some>] #![allow(unused_variables)] use std::ffi::OsString; diff --git a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs index f698f8835a2..ea1ea1943e9 100644 --- a/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs +++ b/src/test/incremental/add_private_fn_at_krate_root_cc/struct_point.rs @@ -24,7 +24,7 @@ extern crate point; pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -35,7 +35,7 @@ pub mod fn_calls_methods_in_same_impl { pub mod fn_calls_free_fn { use point::{self, Point}; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; point::distance_squared(&x); @@ -46,7 +46,7 @@ pub mod fn_calls_free_fn { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -56,7 +56,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -66,7 +66,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/callee_caller_cross_crate/b.rs b/src/test/incremental/callee_caller_cross_crate/b.rs index 02453740079..084ed232a55 100644 --- a/src/test/incremental/callee_caller_cross_crate/b.rs +++ b/src/test/incremental/callee_caller_cross_crate/b.rs @@ -6,12 +6,12 @@ extern crate a; -#[rustc_dirty(label="typeck", cfg="rpass2")] +#[rustc_clean(except="typeck", cfg="rpass2")] pub fn call_function0() { a::function0(77); } -#[rustc_clean(label="typeck", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] pub fn call_function1() { a::function1(77); } diff --git a/src/test/incremental/change_add_field/struct_point.rs b/src/test/incremental/change_add_field/struct_point.rs index 8d98cfac8a4..3308ea56222 100644 --- a/src/test/incremental/change_add_field/struct_point.rs +++ b/src/test/incremental/change_add_field/struct_point.rs @@ -70,7 +70,7 @@ pub mod point { pub mod fn_with_type_in_sig { use point::Point; - #[rustc_dirty(label="typeck", cfg="cfail2")] + #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")] pub fn boop(p: Option<&Point>) -> f32 { p.map(|p| p.total()).unwrap_or(0.0) } @@ -86,7 +86,7 @@ pub mod fn_with_type_in_sig { pub mod call_fn_with_type_in_sig { use fn_with_type_in_sig; - #[rustc_dirty(label="typeck", cfg="cfail2")] + #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")] pub fn bip() -> f32 { fn_with_type_in_sig::boop(None) } @@ -102,7 +102,7 @@ pub mod call_fn_with_type_in_sig { pub mod fn_with_type_in_body { use point::Point; - #[rustc_dirty(label="typeck", cfg="cfail2")] + #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")] pub fn boop() -> f32 { Point::origin().total() } @@ -115,7 +115,7 @@ pub mod fn_with_type_in_body { pub mod call_fn_with_type_in_body { use fn_with_type_in_body; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn bip() -> f32 { fn_with_type_in_body::boop() } @@ -125,7 +125,7 @@ pub mod call_fn_with_type_in_body { pub mod fn_make_struct { use point::Point; - #[rustc_dirty(label="typeck", cfg="cfail2")] + #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")] pub fn make_origin(p: Point) -> Point { Point { ..p } } @@ -135,7 +135,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_dirty(label="typeck", cfg="cfail2")] + #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -145,7 +145,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_dirty(label="typeck", cfg="cfail2")] + #[rustc_clean(except="typeck,fn_sig,optimized_mir", cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/change_private_fn/struct_point.rs b/src/test/incremental/change_private_fn/struct_point.rs index ba4bf4e7b7d..1791c089cfa 100644 --- a/src/test/incremental/change_private_fn/struct_point.rs +++ b/src/test/incremental/change_private_fn/struct_point.rs @@ -51,7 +51,7 @@ pub mod point { pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -62,7 +62,7 @@ pub mod fn_calls_methods_in_same_impl { pub mod fn_calls_methods_in_another_impl { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn check() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); @@ -73,7 +73,7 @@ pub mod fn_calls_methods_in_another_impl { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -83,7 +83,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -93,7 +93,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/change_private_fn_cc/struct_point.rs b/src/test/incremental/change_private_fn_cc/struct_point.rs index 5072ef609e2..1c27ec3a3f7 100644 --- a/src/test/incremental/change_private_fn_cc/struct_point.rs +++ b/src/test/incremental/change_private_fn_cc/struct_point.rs @@ -23,7 +23,7 @@ extern crate point; pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -34,7 +34,7 @@ pub mod fn_calls_methods_in_same_impl { pub mod fn_calls_methods_in_another_impl { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn check() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); @@ -45,7 +45,7 @@ pub mod fn_calls_methods_in_another_impl { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -55,7 +55,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -65,7 +65,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/change_private_impl_method/struct_point.rs b/src/test/incremental/change_private_impl_method/struct_point.rs index 11ba96a8c8d..cf43e4757cb 100644 --- a/src/test/incremental/change_private_impl_method/struct_point.rs +++ b/src/test/incremental/change_private_impl_method/struct_point.rs @@ -51,7 +51,7 @@ pub mod point { pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -62,7 +62,7 @@ pub mod fn_calls_methods_in_same_impl { pub mod fn_calls_methods_in_another_impl { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn check() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); @@ -73,7 +73,7 @@ pub mod fn_calls_methods_in_another_impl { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -83,7 +83,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -93,7 +93,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/change_private_impl_method_cc/struct_point.rs b/src/test/incremental/change_private_impl_method_cc/struct_point.rs index 2aeecfc89d5..9fe8b5df93a 100644 --- a/src/test/incremental/change_private_impl_method_cc/struct_point.rs +++ b/src/test/incremental/change_private_impl_method_cc/struct_point.rs @@ -24,7 +24,7 @@ extern crate point; pub mod fn_calls_methods_in_same_impl { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn check() { let x = Point { x: 2.0, y: 2.0 }; x.distance_from_origin(); @@ -35,7 +35,7 @@ pub mod fn_calls_methods_in_same_impl { pub mod fn_calls_methods_in_another_impl { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn dirty() { let mut x = Point { x: 2.0, y: 2.0 }; x.translate(3.0, 3.0); @@ -46,7 +46,7 @@ pub mod fn_calls_methods_in_another_impl { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -56,7 +56,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -66,7 +66,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs index a192dff19e9..1b87b18fcd4 100644 --- a/src/test/incremental/change_pub_inherent_method_body/struct_point.rs +++ b/src/test/incremental/change_pub_inherent_method_body/struct_point.rs @@ -42,7 +42,7 @@ pub mod point { pub mod fn_calls_changed_method { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn check() { let p = Point { x: 2.0, y: 2.0 }; p.distance_from_origin(); @@ -53,7 +53,7 @@ pub mod fn_calls_changed_method { pub mod fn_calls_another_method { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn check() { let p = Point { x: 2.0, y: 2.0 }; p.x(); @@ -64,7 +64,7 @@ pub mod fn_calls_another_method { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -74,7 +74,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -84,7 +84,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs index b0476168555..0a672956768 100644 --- a/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs +++ b/src/test/incremental/change_pub_inherent_method_sig/struct_point.rs @@ -52,7 +52,7 @@ pub mod point { pub mod fn_calls_changed_method { use point::Point; - #[rustc_dirty(label="typeck", cfg="cfail2")] + #[rustc_clean(except="typeck,optimized_mir", cfg="cfail2")] pub fn check() { let p = Point { x: 2.0, y: 2.0 }; p.distance_from_point(None); @@ -63,7 +63,7 @@ pub mod fn_calls_changed_method { pub mod fn_calls_another_method { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn check() { let p = Point { x: 2.0, y: 2.0 }; p.x(); @@ -74,7 +74,7 @@ pub mod fn_calls_another_method { pub mod fn_make_struct { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn make_origin() -> Point { Point { x: 2.0, y: 2.0 } } @@ -84,7 +84,7 @@ pub mod fn_make_struct { pub mod fn_read_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn get_x(p: Point) -> f32 { p.x } @@ -94,7 +94,7 @@ pub mod fn_read_field { pub mod fn_write_field { use point::Point; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn inc_x(p: &mut Point) { p.x += 1.0; } diff --git a/src/test/incremental/crate_hash_reorder.rs b/src/test/incremental/crate_hash_reorder.rs index 6e06e67b668..ca476b4d2db 100644 --- a/src/test/incremental/crate_hash_reorder.rs +++ b/src/test/incremental/crate_hash_reorder.rs @@ -7,9 +7,9 @@ // Check that reordering otherwise identical items is not considered a // change at all. -#[rustc_clean(label = "hir_crate", cfg = "rpass2")] +#[rustc_clean(cfg = "rpass2")] // But removing an item, naturally, is. -#[rustc_dirty(label = "hir_crate", cfg = "rpass3")] +#[rustc_clean(except="hir_crate", cfg = "rpass3")] #[cfg(rpass1)] pub struct X { pub x: u32, diff --git a/src/test/incremental/dirty_clean.rs b/src/test/incremental/dirty_clean.rs index 02c9a0c5798..11d999ab328 100644 --- a/src/test/incremental/dirty_clean.rs +++ b/src/test/incremental/dirty_clean.rs @@ -25,15 +25,24 @@ mod x { mod y { use x; - #[rustc_clean(label="typeck", cfg="cfail2")] + #[rustc_clean( + except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of,fn_sig", + cfg="cfail2", + )] pub fn y() { - //[cfail2]~^ ERROR `typeck(y)` should be clean but is not + //[cfail2]~^ ERROR `hir_owner(y)` should be dirty but is not + //[cfail2]~| ERROR `hir_owner_nodes(y)` should be dirty but is not + //[cfail2]~| ERROR `generics_of(y)` should be dirty but is not + //[cfail2]~| ERROR `predicates_of(y)` should be dirty but is not + //[cfail2]~| ERROR `type_of(y)` should be dirty but is not + //[cfail2]~| ERROR `fn_sig(y)` should be dirty but is not + //[cfail2]~| ERROR `typeck(y)` should be clean but is not x::x(); } } mod z { - #[rustc_dirty(label="typeck", cfg="cfail2")] + #[rustc_clean(except="typeck", cfg="cfail2")] pub fn z() { //[cfail2]~^ ERROR `typeck(z)` should be dirty but is not } diff --git a/src/test/incremental/hashes/call_expressions.rs b/src/test/incremental/hashes/call_expressions.rs index d4511cee75b..d4201400f0f 100644 --- a/src/test/incremental/hashes/call_expressions.rs +++ b/src/test/incremental/hashes/call_expressions.rs @@ -55,12 +55,8 @@ mod change_callee_indirectly_function { #[cfg(not(cfail1))] use super::callee2 as callee; - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] - #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] - #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] - - + #[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] pub fn change_callee_indirectly_function() { callee(1, 2) } diff --git a/src/test/incremental/hashes/enum_defs.rs b/src/test/incremental/hashes/enum_defs.rs index c73c03ca14e..76bff3cad38 100644 --- a/src/test/incremental/hashes/enum_defs.rs +++ b/src/test/incremental/hashes/enum_defs.rs @@ -370,7 +370,7 @@ enum EnumChangeNameOfTypeParameter<S> { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumChangeNameOfTypeParameter<T> { Variant1(T), @@ -386,7 +386,7 @@ enum EnumAddTypeParameter<S> { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddTypeParameter<S, T> { Variant1(S), @@ -402,7 +402,7 @@ enum EnumChangeNameOfLifetimeParameter<'a> { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg="cfail2", except="predicates_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumChangeNameOfLifetimeParameter<'b> { Variant1(&'b u32), @@ -418,7 +418,7 @@ enum EnumAddLifetimeParameter<'a> { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg="cfail2", except="predicates_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddLifetimeParameter<'a, 'b> { Variant1(&'a u32), @@ -435,7 +435,7 @@ enum EnumAddLifetimeParameterBound<'a, 'b> { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg="cfail2", except="generics_of,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddLifetimeParameterBound<'a, 'b: 'a> { Variant1(&'a u32), @@ -450,7 +450,7 @@ enum EnumAddLifetimeBoundToParameter<'a, T> { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg="cfail2", except="type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddLifetimeBoundToParameter<'a, T: 'a> { Variant1(T), @@ -466,7 +466,7 @@ enum EnumAddTraitBound<S> { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddTraitBound<T: Sync> { Variant1(T), @@ -482,7 +482,7 @@ enum EnumAddLifetimeParameterBoundWhere<'a, 'b> { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg="cfail2", except="generics_of,type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,predicates_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddLifetimeParameterBoundWhere<'a, 'b> where 'b: 'a { Variant1(&'a u32), @@ -499,7 +499,7 @@ enum EnumAddLifetimeBoundToParameterWhere<'a, T> { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg="cfail2", except="type_of")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddLifetimeBoundToParameterWhere<'a, T> where T: 'a { Variant1(T), @@ -515,7 +515,7 @@ enum EnumAddTraitBoundWhere<S> { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg="cfail2")] +#[rustc_clean(cfg="cfail2", except="hir_owner,hir_owner_nodes,generics_of,predicates_of,type_of")] #[rustc_clean(cfg="cfail3")] enum EnumAddTraitBoundWhere<T> where T: Sync { Variant1(T), diff --git a/src/test/incremental/hashes/extern_mods.rs b/src/test/incremental/hashes/extern_mods.rs index 93e70d3792c..1160bc376c4 100644 --- a/src/test/incremental/hashes/extern_mods.rs +++ b/src/test/incremental/hashes/extern_mods.rs @@ -21,7 +21,7 @@ extern "C" { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner")] #[rustc_clean(cfg = "cfail3")] extern "C" { pub fn change_function_name2(c: i64) -> i32; @@ -34,7 +34,7 @@ extern "C" { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] extern "C" { pub fn change_parameter_name(d: i64) -> i32; @@ -47,7 +47,7 @@ extern "C" { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] extern "C" { pub fn change_parameter_type(c: i32) -> i32; @@ -60,7 +60,7 @@ extern "C" { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] extern "C" { pub fn change_return_type(c: i32) -> i8; @@ -73,7 +73,7 @@ extern "C" { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] extern "C" { pub fn add_parameter(c: i32, d: i32) -> i32; @@ -86,7 +86,7 @@ extern "C" { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] extern "C" { pub fn add_return_type(c: i32) -> i32; @@ -99,7 +99,7 @@ extern "C" { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] extern "C" { pub fn make_function_variadic(c: i32, ...); @@ -112,7 +112,7 @@ extern "C" { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner")] #[rustc_clean(cfg = "cfail3")] extern "rust-call" { pub fn change_calling_convention(c: i32); @@ -125,7 +125,7 @@ extern "C" { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner")] #[rustc_clean(cfg = "cfail3")] extern "C" { pub fn make_function_public(c: i32); @@ -138,7 +138,7 @@ extern "C" { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg = "cfail2", except = "hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2", except = "hir_owner")] #[rustc_clean(cfg = "cfail3")] extern "C" { pub fn add_function1(c: i32); @@ -153,7 +153,7 @@ extern "C" { } #[cfg(not(cfail1))] -#[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] +#[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] #[link(name = "bar")] extern "C" { @@ -170,7 +170,7 @@ mod indirectly_change_parameter_type { #[cfg(not(cfail1))] use super::c_i64 as c_int; - #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] extern "C" { pub fn indirectly_change_parameter_type(c: c_int); @@ -184,7 +184,7 @@ mod indirectly_change_return_type { #[cfg(not(cfail1))] use super::c_i64 as c_int; - #[rustc_dirty(cfg = "cfail2", except = "hir_owner,hir_owner_nodes")] + #[rustc_clean(cfg = "cfail2")] #[rustc_clean(cfg = "cfail3")] extern "C" { pub fn indirectly_change_return_type() -> c_int; diff --git a/src/test/incremental/hashes/indexing_expressions.rs b/src/test/incremental/hashes/indexing_expressions.rs index 7a8cbc3566e..49ee7a9cac0 100644 --- a/src/test/incremental/hashes/indexing_expressions.rs +++ b/src/test/incremental/hashes/indexing_expressions.rs @@ -20,10 +20,8 @@ fn change_simple_index(slice: &[u32]) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] fn change_simple_index(slice: &[u32]) -> u32 { slice[4] } @@ -37,10 +35,8 @@ fn change_lower_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] fn change_lower_bound(slice: &[u32]) -> &[u32] { &slice[2..5] } @@ -54,10 +50,8 @@ fn change_upper_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] fn change_upper_bound(slice: &[u32]) -> &[u32] { &slice[3..7] } @@ -71,10 +65,8 @@ fn add_lower_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] fn add_lower_bound(slice: &[u32]) -> &[u32] { &slice[3..4] } @@ -88,10 +80,8 @@ fn add_upper_bound(slice: &[u32]) -> &[u32] { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] fn add_upper_bound(slice: &[u32]) -> &[u32] { &slice[3..7] } @@ -105,10 +95,8 @@ fn change_mutability(slice: &mut [u32]) -> u32 { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] fn change_mutability(slice: &mut [u32]) -> u32 { (&slice[3..5])[0] } @@ -122,10 +110,8 @@ fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] +#[rustc_clean(except="hir_owner_nodes,typeck", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] fn exclusive_to_inclusive_range(slice: &[u32]) -> &[u32] { &slice[3..=7] } diff --git a/src/test/incremental/hashes/inherent_impls.rs b/src/test/incremental/hashes/inherent_impls.rs index 70ce81bd473..284a95f1a68 100644 --- a/src/test/incremental/hashes/inherent_impls.rs +++ b/src/test/incremental/hashes/inherent_impls.rs @@ -103,7 +103,10 @@ impl Foo { #[rustc_clean(cfg="cfail2", except="hir_owner")] #[rustc_clean(cfg="cfail3")] impl Foo { - #[rustc_dirty(cfg="cfail2", except="type_of,predicates_of,promoted_mir")] + #[rustc_clean( + cfg="cfail2", + except="hir_owner,hir_owner_nodes,fn_sig,generics_of,typeck,associated_item,optimized_mir", + )] #[rustc_clean(cfg="cfail3")] pub fn method_selfness(&self) { } } diff --git a/src/test/incremental/hashes/struct_defs.rs b/src/test/incremental/hashes/struct_defs.rs index 1339a1e5bf2..0ce5aeaaf50 100644 --- a/src/test/incremental/hashes/struct_defs.rs +++ b/src/test/incremental/hashes/struct_defs.rs @@ -24,16 +24,8 @@ pub struct LayoutPacked; #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_dirty(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="type_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[repr(packed)] pub struct LayoutPacked; @@ -41,16 +33,8 @@ pub struct LayoutPacked; struct LayoutC; #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_dirty(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="type_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] #[repr(C)] struct LayoutC; @@ -61,16 +45,8 @@ struct LayoutC; struct TupleStructFieldType(i32); #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] // Note that changing the type of a field does not change the type of the struct or enum, but // adding/removing fields or changing a fields name or visibility does. struct TupleStructFieldType( @@ -84,16 +60,8 @@ struct TupleStructFieldType( struct TupleStructAddField(i32); #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_dirty(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] struct TupleStructAddField( i32, u32 @@ -106,16 +74,8 @@ struct TupleStructAddField( struct TupleStructFieldVisibility(char); #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_dirty(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] struct TupleStructFieldVisibility(pub char); @@ -125,16 +85,8 @@ struct TupleStructFieldVisibility(pub char); struct RecordStructFieldType { x: f32 } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] // Note that changing the type of a field does not change the type of the struct or enum, but // adding/removing fields or changing a fields name or visibility does. struct RecordStructFieldType { @@ -148,16 +100,8 @@ struct RecordStructFieldType { struct RecordStructFieldName { x: f32 } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_dirty(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] struct RecordStructFieldName { y: f32 } @@ -167,16 +111,8 @@ struct RecordStructFieldName { y: f32 } struct RecordStructAddField { x: f32 } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_dirty(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] struct RecordStructAddField { x: f32, y: () } @@ -188,16 +124,8 @@ struct RecordStructAddField { struct RecordStructFieldVisibility { x: f32 } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_dirty(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] struct RecordStructFieldVisibility { pub x: f32 } @@ -209,16 +137,8 @@ struct RecordStructFieldVisibility { struct AddLifetimeParameter<'a>(&'a f32, &'a f64); #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_dirty(label="type_of", cfg="cfail2")] -#[rustc_dirty(label="generics_of", cfg="cfail2")] -#[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64); @@ -228,16 +148,8 @@ struct AddLifetimeParameter<'a, 'b>(&'a f32, &'b f64); struct AddLifetimeParameterBound<'a, 'b>(&'a f32, &'b f64); #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_dirty(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] struct AddLifetimeParameterBound<'a, 'b: 'a>( &'a f32, &'b f64 @@ -247,16 +159,8 @@ struct AddLifetimeParameterBound<'a, 'b: 'a>( struct AddLifetimeParameterBoundWhereClause<'a, 'b>(&'a f32, &'b f64); #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_dirty(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] struct AddLifetimeParameterBoundWhereClause<'a, 'b>( &'a f32, &'b f64) @@ -269,16 +173,8 @@ struct AddLifetimeParameterBoundWhereClause<'a, 'b>( struct AddTypeParameter<T1>(T1, T1); #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_dirty(label="type_of", cfg="cfail2")] -#[rustc_dirty(label="generics_of", cfg="cfail2")] -#[rustc_dirty(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,type_of,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] struct AddTypeParameter<T1, T2>( // The field contains the parent's Generics, so it's dirty even though its // type hasn't changed. @@ -293,16 +189,8 @@ struct AddTypeParameter<T1, T2>( struct AddTypeParameterBound<T>(T); #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_dirty(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] struct AddTypeParameterBound<T: Send>( T ); @@ -312,16 +200,8 @@ struct AddTypeParameterBound<T: Send>( struct AddTypeParameterBoundWhereClause<T>(T); #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_dirty(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] struct AddTypeParameterBoundWhereClause<T>( T ) where T: Sync; @@ -332,16 +212,8 @@ struct AddTypeParameterBoundWhereClause<T>( // fingerprint is stable (i.e., that there are no random influences like memory // addresses taken into account by the hashing algorithm). // Note: there is no #[cfg(...)], so this is ALWAYS compiled -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] pub struct EmptyStruct; @@ -351,16 +223,8 @@ pub struct EmptyStruct; struct Visibility; #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] -#[rustc_clean(label="type_of", cfg="cfail2")] -#[rustc_clean(label="generics_of", cfg="cfail2")] -#[rustc_clean(label="predicates_of", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] -#[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] -#[rustc_clean(label="type_of", cfg="cfail3")] -#[rustc_clean(label="generics_of", cfg="cfail3")] -#[rustc_clean(label="predicates_of", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] pub struct Visibility; struct ReferencedType1; @@ -373,16 +237,8 @@ mod tuple_struct_change_field_type_indirectly { #[cfg(not(cfail1))] use super::ReferencedType2 as FieldType; - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] - #[rustc_clean(label="type_of", cfg="cfail2")] - #[rustc_clean(label="generics_of", cfg="cfail2")] - #[rustc_clean(label="predicates_of", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] - #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] - #[rustc_clean(label="type_of", cfg="cfail3")] - #[rustc_clean(label="generics_of", cfg="cfail3")] - #[rustc_clean(label="predicates_of", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] struct TupleStruct( FieldType ); @@ -396,16 +252,8 @@ mod record_struct_change_field_type_indirectly { #[cfg(not(cfail1))] use super::ReferencedType2 as FieldType; - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] - #[rustc_clean(label="type_of", cfg="cfail2")] - #[rustc_clean(label="generics_of", cfg="cfail2")] - #[rustc_clean(label="predicates_of", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] - #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] - #[rustc_clean(label="type_of", cfg="cfail3")] - #[rustc_clean(label="generics_of", cfg="cfail3")] - #[rustc_clean(label="predicates_of", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] struct RecordStruct { _x: FieldType } @@ -424,16 +272,8 @@ mod change_trait_bound_indirectly { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] - #[rustc_clean(label="type_of", cfg="cfail2")] - #[rustc_clean(label="generics_of", cfg="cfail2")] - #[rustc_dirty(label="predicates_of", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] - #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] - #[rustc_clean(label="type_of", cfg="cfail3")] - #[rustc_clean(label="generics_of", cfg="cfail3")] - #[rustc_clean(label="predicates_of", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] struct Struct<T: Trait>(T); } @@ -444,15 +284,7 @@ mod change_trait_bound_indirectly_in_where_clause { #[cfg(not(cfail1))] use super::ReferencedTrait2 as Trait; - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] - #[rustc_clean(label="type_of", cfg="cfail2")] - #[rustc_clean(label="generics_of", cfg="cfail2")] - #[rustc_dirty(label="predicates_of", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] - #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] - #[rustc_clean(label="type_of", cfg="cfail3")] - #[rustc_clean(label="generics_of", cfg="cfail3")] - #[rustc_clean(label="predicates_of", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] struct Struct<T>(T) where T : Trait; } diff --git a/src/test/incremental/hashes/trait_defs.rs b/src/test/incremental/hashes/trait_defs.rs index 4dab032e47f..a604ca5ca82 100644 --- a/src/test/incremental/hashes/trait_defs.rs +++ b/src/test/incremental/hashes/trait_defs.rs @@ -25,8 +25,8 @@ trait TraitVisibility { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] pub trait TraitVisibility { } @@ -36,8 +36,8 @@ pub trait TraitVisibility { } trait TraitUnsafety { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] unsafe trait TraitUnsafety { } @@ -48,8 +48,8 @@ trait TraitAddMethod { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] pub trait TraitAddMethod { fn method(); } @@ -63,8 +63,8 @@ trait TraitChangeMethodName { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitChangeMethodName { fn methodChanged(); } @@ -78,11 +78,11 @@ trait TraitAddReturnType { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddReturnType { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method() -> u32; } @@ -95,11 +95,11 @@ trait TraitChangeReturnType { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitChangeReturnType { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method() -> u64; } @@ -112,11 +112,11 @@ trait TraitAddParameterToMethod { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddParameterToMethod { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method(a: u32); } @@ -130,18 +130,16 @@ trait TraitChangeMethodParameterName { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitChangeMethodParameterName { // FIXME(#38501) This should preferably always be clean. - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method(b: u32); - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] - #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] - #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] + #[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn with_default(y: i32) {} } @@ -154,11 +152,11 @@ trait TraitChangeMethodParameterType { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitChangeMethodParameterType { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method(a: i64); } @@ -171,11 +169,11 @@ trait TraitChangeMethodParameterTypeRef { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitChangeMethodParameterTypeRef { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method(a: &mut i32); } @@ -188,11 +186,11 @@ trait TraitChangeMethodParametersOrder { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitChangeMethodParametersOrder { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method(b: i64, a: i32); } @@ -205,11 +203,11 @@ trait TraitAddMethodAutoImplementation { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddMethodAutoImplementation { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method() { } } @@ -223,8 +221,8 @@ trait TraitChangeOrderOfMethods { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitChangeOrderOfMethods { fn method1(); fn method0(); @@ -239,11 +237,11 @@ trait TraitChangeModeSelfRefToMut { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitChangeModeSelfRefToMut { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method(&mut self); } @@ -255,13 +253,11 @@ trait TraitChangeModeSelfOwnToMut: Sized { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitChangeModeSelfOwnToMut: Sized { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] - #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] - #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method(mut self) {} } @@ -273,11 +269,11 @@ trait TraitChangeModeSelfOwnToRef { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitChangeModeSelfOwnToRef { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method(&self); } @@ -290,11 +286,11 @@ trait TraitAddUnsafeModifier { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddUnsafeModifier { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] unsafe fn method(); } @@ -307,11 +303,11 @@ trait TraitAddExternModifier { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddExternModifier { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] extern "C" fn method(); } @@ -324,11 +320,11 @@ trait TraitChangeExternCToRustIntrinsic { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitChangeExternCToRustIntrinsic { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] extern "stdcall" fn method(); } @@ -341,11 +337,11 @@ trait TraitAddTypeParameterToMethod { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddTypeParameterToMethod { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,generics_of,predicates_of,type_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method<T>(); } @@ -358,11 +354,11 @@ trait TraitAddLifetimeParameterToMethod { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddLifetimeParameterToMethod { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig,generics_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method<'a>(); } @@ -379,11 +375,11 @@ trait TraitAddTraitBoundToMethodTypeParameter { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddTraitBoundToMethodTypeParameter { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method<T: ReferencedTrait0>(); } @@ -396,11 +392,11 @@ trait TraitAddBuiltinBoundToMethodTypeParameter { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddBuiltinBoundToMethodTypeParameter { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method<T: Sized>(); } @@ -413,11 +409,14 @@ trait TraitAddLifetimeBoundToMethodLifetimeParameter { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddLifetimeBoundToMethodLifetimeParameter { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean( + except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", + cfg="cfail2", + )] + #[rustc_clean(cfg="cfail3")] fn method<'a, 'b: 'a>(a: &'a u32, b: &'b u32); } @@ -430,11 +429,11 @@ trait TraitAddSecondTraitBoundToMethodTypeParameter { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondTraitBoundToMethodTypeParameter { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method<T: ReferencedTrait0 + ReferencedTrait1>(); } @@ -447,11 +446,11 @@ trait TraitAddSecondBuiltinBoundToMethodTypeParameter { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondBuiltinBoundToMethodTypeParameter { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method<T: Sized + Sync>(); } @@ -464,11 +463,14 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean( + except="hir_owner,hir_owner_nodes,generics_of,predicates_of,fn_sig,type_of", + cfg="cfail2", + )] + #[rustc_clean(cfg="cfail3")] fn method<'a, 'b, 'c: 'a + 'b>(a: &'a u32, b: &'b u32, c: &'c u32); } @@ -478,14 +480,14 @@ trait TraitAddSecondLifetimeBoundToMethodLifetimeParameter { #[cfg(cfail1)] trait TraitAddAssociatedType { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method(); } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddAssociatedType { type Associated; @@ -506,11 +508,11 @@ trait TraitAddTraitBoundToAssociatedType { // Apparently the type bound contributes to the predicates of the trait, but // does not change the associated item itself. #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddTraitBoundToAssociatedType { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] type Associated: ReferencedTrait0; fn method(); @@ -527,11 +529,11 @@ trait TraitAddLifetimeBoundToAssociatedType<'a> { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddLifetimeBoundToAssociatedType<'a> { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] type Associated: 'a; fn method(); @@ -548,11 +550,11 @@ trait TraitAddDefaultToAssociatedType { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddDefaultToAssociatedType { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] type Associated = ReferenceType0; fn method(); @@ -567,8 +569,8 @@ trait TraitAddAssociatedConstant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddAssociatedConstant { const Value: u32; @@ -586,15 +588,15 @@ trait TraitAddInitializerToAssociatedConstant { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddInitializerToAssociatedConstant { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] const Value: u32 = 1; - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method(); } @@ -609,15 +611,15 @@ trait TraitChangeTypeOfAssociatedConstant { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitChangeTypeOfAssociatedConstant { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,type_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] const Value: f64; - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method(); } @@ -628,8 +630,8 @@ trait TraitChangeTypeOfAssociatedConstant { trait TraitAddSuperTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSuperTrait : ReferencedTrait0 { } @@ -639,8 +641,8 @@ trait TraitAddSuperTrait : ReferencedTrait0 { } trait TraitAddBuiltiBound { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddBuiltiBound : Send { } @@ -650,8 +652,8 @@ trait TraitAddBuiltiBound : Send { } trait TraitAddStaticLifetimeBound { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddStaticLifetimeBound : 'static { } @@ -661,16 +663,16 @@ trait TraitAddStaticLifetimeBound : 'static { } trait TraitAddTraitAsSecondBound : ReferencedTrait0 { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddTraitAsSecondBound : ReferencedTrait0 + ReferencedTrait1 { } #[cfg(cfail1)] trait TraitAddTraitAsSecondBoundFromBuiltin : Send { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } @@ -680,16 +682,16 @@ trait TraitAddTraitAsSecondBoundFromBuiltin : Send + ReferencedTrait0 { } trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddBuiltinBoundAsSecondBound : ReferencedTrait0 + Send { } #[cfg(cfail1)] trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin : Send { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } @@ -699,16 +701,16 @@ trait TraitAddBuiltinBoundAsSecondBoundFromBuiltin: Send + Copy { } trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddStaticBoundAsSecondBound : ReferencedTrait0 + 'static { } #[cfg(cfail1)] trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } @@ -718,8 +720,8 @@ trait TraitAddStaticBoundAsSecondBoundFromBuiltin : Send + 'static { } trait TraitAddTypeParameterToTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddTypeParameterToTrait<T> { } @@ -729,8 +731,8 @@ trait TraitAddTypeParameterToTrait<T> { } trait TraitAddLifetimeParameterToTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddLifetimeParameterToTrait<'a> { } @@ -740,8 +742,8 @@ trait TraitAddLifetimeParameterToTrait<'a> { } trait TraitAddTraitBoundToTypeParameterOfTrait<T> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { } @@ -751,8 +753,8 @@ trait TraitAddTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { } trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } @@ -762,8 +764,8 @@ trait TraitAddLifetimeBoundToTypeParameterOfTrait<'a, T: 'a> { } trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a, 'b> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { } @@ -773,8 +775,8 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b> { } trait TraitAddBuiltinBoundToTypeParameterOfTrait<T> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddBuiltinBoundToTypeParameterOfTrait<T: Send> { } @@ -784,8 +786,8 @@ trait TraitAddBuiltinBoundToTypeParameterOfTrait<T: Send> { } trait TraitAddSecondTypeParameterToTrait<T> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondTypeParameterToTrait<T, S> { } @@ -795,8 +797,8 @@ trait TraitAddSecondTypeParameterToTrait<T, S> { } trait TraitAddSecondLifetimeParameterToTrait<'a> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { } @@ -806,8 +808,8 @@ trait TraitAddSecondLifetimeParameterToTrait<'a, 'b> { } trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0 + ReferencedTrait1> { } @@ -817,8 +819,8 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTrait<T: ReferencedTrait0 + Refer trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } @@ -828,8 +830,8 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTrait<'a, 'b, T: 'a + 'b> { } trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b, 'b, 'c> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> { } @@ -839,8 +841,8 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTrait<'a: 'b + 'c, 'b, 'c> trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait<T: Send> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondBuiltinBoundToTypeParameterOfTrait<T: Send + Sync> { } @@ -855,8 +857,8 @@ struct ReferenceType1 {} trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0 { } @@ -866,8 +868,8 @@ trait TraitAddTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0 trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } @@ -877,8 +879,8 @@ trait TraitAddLifetimeBoundToTypeParameterOfTraitWhere<'a, T> where T: 'a { } trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b { } @@ -888,8 +890,8 @@ trait TraitAddLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b> where 'a: 'b trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { } @@ -899,8 +901,8 @@ trait TraitAddBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { } trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0 { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T> where T: ReferencedTrait0 + ReferencedTrait1 { } @@ -911,8 +913,8 @@ trait TraitAddSecondTraitBoundToTypeParameterOfTraitWhere<T> trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,generics_of,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: 'a + 'b { } @@ -922,8 +924,8 @@ trait TraitAddSecondLifetimeBoundToTypeParameterOfTraitWhere<'a, 'b, T> where T: trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> where 'a: 'b + 'c { } @@ -933,8 +935,8 @@ trait TraitAddSecondLifetimeBoundToLifetimeParameterOfTraitWhere<'a, 'b, 'c> whe trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] trait TraitAddSecondBuiltinBoundToTypeParameterOfTraitWhere<T> where T: Send + Sync { } @@ -945,11 +947,11 @@ mod change_return_type_of_method_indirectly_use { #[cfg(not(cfail1))] use super::ReferenceType1 as ReturnType; - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] trait TraitChangeReturnType { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method() -> ReturnType; } } @@ -963,11 +965,11 @@ mod change_method_parameter_type_indirectly_by_use { #[cfg(not(cfail1))] use super::ReferenceType1 as ArgType; - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] trait TraitChangeArgType { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,fn_sig", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method(a: ArgType); } } @@ -981,11 +983,11 @@ mod change_method_parameter_type_bound_indirectly_by_use { #[cfg(not(cfail1))] use super::ReferencedTrait1 as Bound; - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] trait TraitChangeBoundOfMethodTypeParameter { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method<T: Bound>(a: T); } } @@ -1000,11 +1002,11 @@ mod change_method_parameter_type_bound_indirectly_by_use_where { #[cfg(not(cfail1))] use super::ReferencedTrait1 as Bound; - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] trait TraitChangeBoundOfMethodTypeParameterWhere { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method<T>(a: T) where T: Bound; } } @@ -1018,8 +1020,8 @@ mod change_method_type_parameter_bound_indirectly { #[cfg(not(cfail1))] use super::ReferencedTrait1 as Bound; - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] trait TraitChangeTraitBound<T: Bound> { fn method(a: T); } @@ -1035,8 +1037,8 @@ mod change_method_type_parameter_bound_indirectly_where { #[cfg(not(cfail1))] use super::ReferencedTrait1 as Bound; - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,predicates_of", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] trait TraitChangeTraitBoundWhere<T> where T: Bound { fn method(a: T); } diff --git a/src/test/incremental/hashes/trait_impls.rs b/src/test/incremental/hashes/trait_impls.rs index e9118da5a61..c9a3de1f6ae 100644 --- a/src/test/incremental/hashes/trait_impls.rs +++ b/src/test/incremental/hashes/trait_impls.rs @@ -30,18 +30,18 @@ impl ChangeMethodNameTrait for Foo { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] pub trait ChangeMethodNameTrait { - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(cfg="cfail3")] fn method_name2(); } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl ChangeMethodNameTrait for Foo { - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(cfg="cfail3")] fn method_name2() { } } @@ -59,13 +59,11 @@ impl ChangeMethodBodyTrait for Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl ChangeMethodBodyTrait for Foo { - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] - #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] - #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] + #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method_name() { () } @@ -86,13 +84,11 @@ impl ChangeMethodBodyTraitInlined for Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl ChangeMethodBodyTraitInlined for Foo { - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] - #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] - #[rustc_clean(label="hir_owner_nodes", cfg="cfail3")] + #[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] #[inline] fn method_name() { panic!() @@ -117,11 +113,14 @@ pub trait ChangeMethodSelfnessTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl ChangeMethodSelfnessTrait for Foo { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean( + except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", + cfg="cfail2", + )] + #[rustc_clean(cfg="cfail3")] fn method_name(&self) { () } @@ -145,11 +144,14 @@ pub trait RemoveMethodSelfnessTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl RemoveMethodSelfnessTrait for Foo { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean( + except="hir_owner,hir_owner_nodes,associated_item,generics_of,fn_sig,typeck,optimized_mir", + cfg="cfail2", + )] + #[rustc_clean(cfg="cfail3")] fn method_name() {} } @@ -171,11 +173,11 @@ pub trait ChangeMethodSelfmutnessTrait { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl ChangeMethodSelfmutnessTrait for Foo { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method_name(&mut self) {} } @@ -197,8 +199,8 @@ pub trait ChangeItemKindTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl ChangeItemKindTrait for Foo { type name = (); } @@ -223,8 +225,8 @@ pub trait RemoveItemTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl RemoveItemTrait for Foo { type TypeName = (); } @@ -248,8 +250,8 @@ pub trait AddItemTrait { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,associated_item_def_ids", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl AddItemTrait for Foo { type TypeName = (); fn method_name() { } @@ -268,17 +270,17 @@ impl ChangeHasValueTrait for Foo { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] pub trait ChangeHasValueTrait { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,associated_item", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method_name() { } } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl ChangeHasValueTrait for Foo { fn method_name() { } } @@ -295,11 +297,11 @@ impl AddDefaultTrait for Foo { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl AddDefaultTrait for Foo { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,associated_item", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] default fn method_name() { } } @@ -321,11 +323,11 @@ pub trait AddArgumentTrait { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl AddArgumentTrait for Foo { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method_name(&self, _x: u32) { } } @@ -347,11 +349,11 @@ pub trait ChangeArgumentTypeTrait { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl ChangeArgumentTypeTrait for Foo { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,fn_sig,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn method_name(&self, _x: char) { } } @@ -370,11 +372,14 @@ impl AddTypeParameterToImpl<u32> for Bar<u32> { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,generics_of,impl_trait_ref", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl<T> AddTypeParameterToImpl<T> for Bar<T> { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean( + except="hir_owner,hir_owner_nodes,generics_of,fn_sig,type_of,typeck,optimized_mir", + cfg="cfail2", + )] + #[rustc_clean(cfg="cfail3")] fn id(t: T) -> T { t } } @@ -391,11 +396,11 @@ impl ChangeSelfTypeOfImpl for u32 { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,impl_trait_ref", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl ChangeSelfTypeOfImpl for u64 { - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(except="fn_sig,typeck,optimized_mir", cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn id(self) -> Self { self } } @@ -412,11 +417,11 @@ impl<T> AddLifetimeBoundToImplParameter for T { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl<T: 'static> AddLifetimeBoundToImplParameter for T { - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn id(self) -> Self { self } } @@ -433,11 +438,11 @@ impl<T> AddTraitBoundToImplParameter for T { } #[cfg(not(cfail1))] -#[rustc_dirty(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(except="hir_owner,hir_owner_nodes", cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl<T: Clone> AddTraitBoundToImplParameter for T { - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] fn id(self) -> Self { self } } @@ -454,11 +459,11 @@ impl AddNoMangleToMethod for Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl AddNoMangleToMethod for Foo { - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] #[no_mangle] fn add_no_mangle_to_method(&self) { } } @@ -475,11 +480,11 @@ impl MakeMethodInline for Foo { } #[cfg(not(cfail1))] -#[rustc_clean(label="hir_owner", cfg="cfail2")] -#[rustc_clean(label="hir_owner", cfg="cfail3")] +#[rustc_clean(cfg="cfail2")] +#[rustc_clean(cfg="cfail3")] impl MakeMethodInline for Foo { - #[rustc_clean(label="hir_owner", cfg="cfail2")] - #[rustc_clean(label="hir_owner", cfg="cfail3")] + #[rustc_clean(cfg="cfail2")] + #[rustc_clean(cfg="cfail3")] #[inline] fn make_method_inline(&self) -> u8 { 0 } } diff --git a/src/test/incremental/hello_world.rs b/src/test/incremental/hello_world.rs index 4c60d7bd9d5..d5ec6e92bc0 100644 --- a/src/test/incremental/hello_world.rs +++ b/src/test/incremental/hello_world.rs @@ -21,7 +21,7 @@ mod x { mod y { use x; - #[rustc_clean(label="typeck", cfg="rpass2")] + #[rustc_clean(cfg="rpass2")] pub fn yyyy() { x::xxxx(); } @@ -30,7 +30,7 @@ mod y { mod z { use y; - #[rustc_clean(label="typeck", cfg="rpass2")] + #[rustc_clean(cfg="rpass2")] pub fn z() { y::yyyy(); } diff --git a/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs b/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs index 91a9f63d39b..b31f60e972b 100644 --- a/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs +++ b/src/test/incremental/hygiene/auxiliary/cached_hygiene.rs @@ -13,7 +13,7 @@ macro_rules! first_macro { } } -#[rustc_dirty(label="typeck", cfg="rpass2")] +#[rustc_clean(except="hir_owner_nodes,typeck,optimized_mir,promoted_mir", cfg="rpass2")] #[inline(always)] pub fn changed_fn() { // This will cause additional hygiene to be generate, diff --git a/src/test/incremental/ich_method_call_trait_scope.rs b/src/test/incremental/ich_method_call_trait_scope.rs index 6d7d446cb7c..5566506c039 100644 --- a/src/test/incremental/ich_method_call_trait_scope.rs +++ b/src/test/incremental/ich_method_call_trait_scope.rs @@ -26,16 +26,12 @@ mod mod3 { #[cfg(rpass2)] use Trait2; - #[rustc_clean(label="hir_owner", cfg="rpass2")] - #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")] - #[rustc_dirty(label="typeck", cfg="rpass2")] + #[rustc_clean(except="typeck", cfg="rpass2")] fn bar() { ().method(); } - #[rustc_clean(label="hir_owner", cfg="rpass2")] - #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")] - #[rustc_clean(label="typeck", cfg="rpass2")] + #[rustc_clean(cfg="rpass2")] fn baz() { 22; // no method call, traits in scope don't matter } diff --git a/src/test/incremental/ich_nested_items.rs b/src/test/incremental/ich_nested_items.rs index 8df54467e5e..379c09575ed 100644 --- a/src/test/incremental/ich_nested_items.rs +++ b/src/test/incremental/ich_nested_items.rs @@ -8,14 +8,12 @@ #![crate_type = "rlib"] #![feature(rustc_attrs)] -#[rustc_clean(label = "hir_owner", cfg = "cfail2")] -#[rustc_dirty(label = "hir_owner_nodes", cfg = "cfail2")] +#[rustc_clean(except = "hir_owner_nodes", cfg = "cfail2")] pub fn foo() { #[cfg(cfail1)] pub fn baz() {} // order is different... - #[rustc_clean(label = "hir_owner", cfg = "cfail2")] - #[rustc_clean(label = "hir_owner_nodes", cfg = "cfail2")] + #[rustc_clean(cfg = "cfail2")] pub fn bar() {} // but that doesn't matter. #[cfg(cfail2)] diff --git a/src/test/incremental/ich_resolve_results.rs b/src/test/incremental/ich_resolve_results.rs index 1fb0f8aa84d..e6ab6bcebae 100644 --- a/src/test/incremental/ich_resolve_results.rs +++ b/src/test/incremental/ich_resolve_results.rs @@ -29,18 +29,14 @@ mod mod3 { #[cfg(rpass3)] use mod2::Foo; - #[rustc_clean(label="hir_owner", cfg="rpass2")] - #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")] - #[rustc_clean(label="hir_owner", cfg="rpass3")] - #[rustc_dirty(label="hir_owner_nodes", cfg="rpass3")] + #[rustc_clean(cfg="rpass2")] + #[rustc_clean(except="hir_owner_nodes,typeck", cfg="rpass3")] fn in_expr() { Foo(0); } - #[rustc_clean(label="hir_owner", cfg="rpass2")] - #[rustc_clean(label="hir_owner_nodes", cfg="rpass2")] - #[rustc_clean(label="hir_owner", cfg="rpass3")] - #[rustc_dirty(label="hir_owner_nodes", cfg="rpass3")] + #[rustc_clean(cfg="rpass2")] + #[rustc_clean(except="hir_owner_nodes,typeck", cfg="rpass3")] fn in_type() { test::<Foo>(); } diff --git a/src/test/incremental/link_order/auxiliary/my_lib.rs b/src/test/incremental/link_order/auxiliary/my_lib.rs new file mode 100644 index 00000000000..57cde5f7c6e --- /dev/null +++ b/src/test/incremental/link_order/auxiliary/my_lib.rs @@ -0,0 +1,3 @@ +// no-prefer-dynamic +//[cfail1] compile-flags: -lbar -lfoo --crate-type lib +//[cfail2] compile-flags: -lfoo -lbar --crate-type lib diff --git a/src/test/incremental/link_order/main.rs b/src/test/incremental/link_order/main.rs new file mode 100644 index 00000000000..d211c295bc4 --- /dev/null +++ b/src/test/incremental/link_order/main.rs @@ -0,0 +1,12 @@ +// aux-build:my_lib.rs +// error-pattern: error: linking with +// revisions:cfail1 cfail2 +// compile-flags:-Z query-dep-graph + +// Tests that re-ordering the `-l` arguments used +// when compiling an external dependency does not lead to +// an 'unstable fingerprint' error. + +extern crate my_lib; + +fn main() {} diff --git a/src/test/incremental/rlib_cross_crate/b.rs b/src/test/incremental/rlib_cross_crate/b.rs index 73846712b59..639cfc918cb 100644 --- a/src/test/incremental/rlib_cross_crate/b.rs +++ b/src/test/incremental/rlib_cross_crate/b.rs @@ -12,15 +12,15 @@ extern crate a; -#[rustc_dirty(label="typeck", cfg="rpass2")] -#[rustc_clean(label="typeck", cfg="rpass3")] +#[rustc_clean(except="typeck,optimized_mir", cfg="rpass2")] +#[rustc_clean(cfg="rpass3")] pub fn use_X() -> u32 { let x: a::X = 22; x as u32 } -#[rustc_clean(label="typeck", cfg="rpass2")] -#[rustc_clean(label="typeck", cfg="rpass3")] +#[rustc_clean(cfg="rpass2")] +#[rustc_clean(cfg="rpass3")] pub fn use_Y() { let x: a::Y = 'c'; } diff --git a/src/test/incremental/source_loc_macros.rs b/src/test/incremental/source_loc_macros.rs index f18d2fdaf0a..e5f04e5dc58 100644 --- a/src/test/incremental/source_loc_macros.rs +++ b/src/test/incremental/source_loc_macros.rs @@ -7,26 +7,22 @@ #![feature(rustc_attrs)] -#[rustc_clean(label="hir_owner", cfg="rpass2")] -#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] fn line_same() { let _ = line!(); } -#[rustc_clean(label="hir_owner", cfg="rpass2")] -#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] fn col_same() { let _ = column!(); } -#[rustc_clean(label="hir_owner", cfg="rpass2")] -#[rustc_clean(label="hir_owner_nodes", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] fn file_same() { let _ = file!(); } -#[rustc_clean(label="hir_owner", cfg="rpass2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="rpass2")] fn line_different() { #[cfg(rpass1)] { @@ -38,8 +34,7 @@ fn line_different() { } } -#[rustc_clean(label="hir_owner", cfg="rpass2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")] +#[rustc_clean(except="hir_owner_nodes,optimized_mir", cfg="rpass2")] fn col_different() { #[cfg(rpass1)] { diff --git a/src/test/incremental/span_hash_stable/auxiliary/sub1.rs b/src/test/incremental/span_hash_stable/auxiliary/sub1.rs index 2927ddec4e5..70e2ea06b7e 100644 --- a/src/test/incremental/span_hash_stable/auxiliary/sub1.rs +++ b/src/test/incremental/span_hash_stable/auxiliary/sub1.rs @@ -1,4 +1,4 @@ -#[rustc_clean(label="hir_owner", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] pub struct SomeType { pub x: u32, pub y: i64, diff --git a/src/test/incremental/span_hash_stable/auxiliary/sub2.rs b/src/test/incremental/span_hash_stable/auxiliary/sub2.rs index aa635077db8..1167cdb0a82 100644 --- a/src/test/incremental/span_hash_stable/auxiliary/sub2.rs +++ b/src/test/incremental/span_hash_stable/auxiliary/sub2.rs @@ -1,4 +1,4 @@ -#[rustc_clean(label="hir_owner", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] pub struct SomeOtherType { pub a: i32, pub b: u64, diff --git a/src/test/incremental/spans_significant_w_debuginfo.rs b/src/test/incremental/spans_significant_w_debuginfo.rs index aff2be830ff..8506636e22b 100644 --- a/src/test/incremental/spans_significant_w_debuginfo.rs +++ b/src/test/incremental/spans_significant_w_debuginfo.rs @@ -12,6 +12,5 @@ pub fn main() {} #[cfg(rpass2)] -#[rustc_dirty(label="hir_owner", cfg="rpass2")] -#[rustc_dirty(label="hir_owner_nodes", cfg="rpass2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir", cfg="rpass2")] pub fn main() {} diff --git a/src/test/incremental/spans_significant_w_panic.rs b/src/test/incremental/spans_significant_w_panic.rs index 37728af9516..a29b61ab153 100644 --- a/src/test/incremental/spans_significant_w_panic.rs +++ b/src/test/incremental/spans_significant_w_panic.rs @@ -13,7 +13,7 @@ pub fn main() { } #[cfg(rpass2)] -#[rustc_dirty(label="optimized_mir", cfg="rpass2")] +#[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir", cfg="rpass2")] pub fn main() { let _ = 0u8 + 1; } diff --git a/src/test/incremental/string_constant.rs b/src/test/incremental/string_constant.rs index 2fc72529431..866f51d759e 100644 --- a/src/test/incremental/string_constant.rs +++ b/src/test/incremental/string_constant.rs @@ -18,8 +18,7 @@ pub mod x { } #[cfg(cfail2)] - #[rustc_dirty(label="hir_owner_nodes", cfg="cfail2")] - #[rustc_dirty(label="optimized_mir", cfg="cfail2")] + #[rustc_clean(except="hir_owner,hir_owner_nodes,optimized_mir,promoted_mir", cfg="cfail2")] pub fn x() { println!("{}", "2"); } @@ -28,8 +27,7 @@ pub mod x { pub mod y { use x; - #[rustc_clean(label="typeck", cfg="cfail2")] - #[rustc_clean(label="optimized_mir", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn y() { x::x(); } @@ -38,8 +36,7 @@ pub mod y { pub mod z { use y; - #[rustc_clean(label="typeck", cfg="cfail2")] - #[rustc_clean(label="optimized_mir", cfg="cfail2")] + #[rustc_clean(cfg="cfail2")] pub fn z() { y::y(); } diff --git a/src/test/incremental/struct_add_field.rs b/src/test/incremental/struct_add_field.rs index 4c29f196f67..720854f1605 100644 --- a/src/test/incremental/struct_add_field.rs +++ b/src/test/incremental/struct_add_field.rs @@ -21,17 +21,17 @@ pub struct Y { pub y: char } -#[rustc_dirty(label="typeck", cfg="rpass2")] +#[rustc_clean(except="fn_sig,typeck", cfg="rpass2")] pub fn use_X(x: X) -> u32 { x.x as u32 } -#[rustc_dirty(label="typeck", cfg="rpass2")] +#[rustc_clean(except="typeck", cfg="rpass2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 } -#[rustc_clean(label="typeck", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_change_field_name.rs b/src/test/incremental/struct_change_field_name.rs index ee88fbdf592..7498d0305e0 100644 --- a/src/test/incremental/struct_change_field_name.rs +++ b/src/test/incremental/struct_change_field_name.rs @@ -24,7 +24,7 @@ pub struct Y { pub y: char } -#[rustc_dirty(label="typeck", cfg="cfail2")] +#[rustc_clean(except="typeck", cfg="cfail2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; //[cfail2]~^ ERROR struct `X` has no field named `x` @@ -32,13 +32,13 @@ pub fn use_X() -> u32 { //[cfail2]~^ ERROR no field `x` on type `X` } -#[rustc_dirty(label="typeck", cfg="cfail2")] +#[rustc_clean(except="typeck", cfg="cfail2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 //[cfail2]~^ ERROR no field `x` on type `X` } -#[rustc_clean(label="typeck", cfg="cfail2")] +#[rustc_clean(cfg="cfail2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_change_field_type.rs b/src/test/incremental/struct_change_field_type.rs index b60b4b311ee..37d2fba9901 100644 --- a/src/test/incremental/struct_change_field_type.rs +++ b/src/test/incremental/struct_change_field_type.rs @@ -24,19 +24,19 @@ pub struct Y { pub y: char } -#[rustc_dirty(label="typeck", cfg="rpass2")] +#[rustc_clean(except="typeck", cfg="rpass2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_dirty(label="typeck", cfg="rpass2")] +#[rustc_clean(except="typeck", cfg="rpass2")] pub fn use_EmbedX(x: EmbedX) -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_clean(label="typeck", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_change_field_type_cross_crate/b.rs b/src/test/incremental/struct_change_field_type_cross_crate/b.rs index 0221d510eab..c78207bcb1a 100644 --- a/src/test/incremental/struct_change_field_type_cross_crate/b.rs +++ b/src/test/incremental/struct_change_field_type_cross_crate/b.rs @@ -8,18 +8,18 @@ extern crate a; use a::*; -#[rustc_dirty(label="typeck", cfg="rpass2")] +#[rustc_clean(except="typeck", cfg="rpass2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_dirty(label="typeck", cfg="rpass2")] +#[rustc_clean(except="typeck", cfg="rpass2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 } -#[rustc_clean(label="typeck", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_change_nothing.rs b/src/test/incremental/struct_change_nothing.rs index 3ab90e966fb..de30c818cfe 100644 --- a/src/test/incremental/struct_change_nothing.rs +++ b/src/test/incremental/struct_change_nothing.rs @@ -24,19 +24,19 @@ pub struct Y { pub y: char } -#[rustc_clean(label="typeck", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] pub fn use_X() -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_clean(label="typeck", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] pub fn use_EmbedX(x: EmbedX) -> u32 { let x: X = X { x: 22 }; x.x as u32 } -#[rustc_clean(label="typeck", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/struct_remove_field.rs b/src/test/incremental/struct_remove_field.rs index f6017b1b1c3..b97a87e0962 100644 --- a/src/test/incremental/struct_remove_field.rs +++ b/src/test/incremental/struct_remove_field.rs @@ -25,17 +25,17 @@ pub struct Y { pub y: char } -#[rustc_dirty(label="typeck", cfg="rpass2")] +#[rustc_clean(except="typeck,fn_sig", cfg="rpass2")] pub fn use_X(x: X) -> u32 { x.x as u32 } -#[rustc_dirty(label="typeck", cfg="rpass2")] +#[rustc_clean(except="typeck", cfg="rpass2")] pub fn use_EmbedX(embed: EmbedX) -> u32 { embed.x.x as u32 } -#[rustc_clean(label="typeck", cfg="rpass2")] +#[rustc_clean(cfg="rpass2")] pub fn use_Y() { let x: Y = Y { y: 'c' }; } diff --git a/src/test/incremental/type_alias_cross_crate/b.rs b/src/test/incremental/type_alias_cross_crate/b.rs index 05c926fdded..f6c2526841c 100644 --- a/src/test/incremental/type_alias_cross_crate/b.rs +++ b/src/test/incremental/type_alias_cross_crate/b.rs @@ -6,15 +6,15 @@ extern crate a; -#[rustc_dirty(label="typeck", cfg="rpass2")] -#[rustc_clean(label="typeck", cfg="rpass3")] +#[rustc_clean(except="typeck", cfg="rpass2")] +#[rustc_clean(cfg="rpass3")] pub fn use_X() -> u32 { let x: a::X = 22; x as u32 } -#[rustc_clean(label="typeck", cfg="rpass2")] -#[rustc_clean(label="typeck", cfg="rpass3")] +#[rustc_clean(cfg="rpass2")] +#[rustc_clean(cfg="rpass3")] pub fn use_Y() { let x: a::Y = 'c'; } diff --git a/src/test/incremental/unchecked_dirty_clean.rs b/src/test/incremental/unchecked_dirty_clean.rs index 3bc8818aa6f..3c8692a302d 100644 --- a/src/test/incremental/unchecked_dirty_clean.rs +++ b/src/test/incremental/unchecked_dirty_clean.rs @@ -4,31 +4,31 @@ #![allow(warnings)] #![feature(rustc_attrs)] -// Sanity check for the dirty-clean system. We add #[rustc_dirty]/#[rustc_clean] +// Sanity check for the dirty-clean system. We add #[rustc_clean] // attributes in places that are not checked and make sure that this causes an // error. fn main() { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute + #[rustc_clean(except="hir_owner", cfg="cfail2")] + //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute { // empty block } - #[rustc_clean(label="hir_owner", cfg="cfail2")] - //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute + #[rustc_clean(cfg="cfail2")] + //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute { // empty block } } struct _Struct { - #[rustc_dirty(label="hir_owner", cfg="cfail2")] - //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute + #[rustc_clean(except="hir_owner", cfg="cfail2")] + //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute _field1: i32, - #[rustc_clean(label="hir_owner", cfg="cfail2")] - //[cfail2]~^ ERROR found unchecked `#[rustc_dirty]` / `#[rustc_clean]` attribute + #[rustc_clean(cfg="cfail2")] + //[cfail2]~^ ERROR found unchecked `#[rustc_clean]` attribute _field2: i32, } diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index 2566d745ecd..8bb5dbc48fe 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -30,7 +30,7 @@ - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 + // + span: $DIR/const-promotion-extern-static.rs:9:31: 9:35 -+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } ++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[55e6]::BAR), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:35 - StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:9:34: 9:35 diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index 093e228a0ce..54f1200a21f 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -32,7 +32,7 @@ - _3 = [move _4]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - _2 = &_3; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 + // + span: $DIR/const-promotion-extern-static.rs:13:31: 13:46 -+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } ++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[55e6]::FOO), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + _2 = &(*_6); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 _1 = move _2 as &[&i32] (Pointer(Unsize)); // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:46 - StorageDead(_4); // scope 0 at $DIR/const-promotion-extern-static.rs:13:45: 13:46 diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff index 0517e7fac40..db6e1369161 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff @@ -31,7 +31,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 - // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff index 0517e7fac40..db6e1369161 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff @@ -31,7 +31,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 - // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &[i32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[8240]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff index 28c80b346e7..d7bc035e667 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff @@ -22,7 +22,7 @@ // + val: Unevaluated(FOO, [], None) // mir::Constant // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main::FOO), const_param_did: None }, substs: [], promoted: None }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[2706]::main::FOO), const_param_did: None }, substs: [], promoted: None }) } _2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 _1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39 StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39 diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff index ae77443e019..4e19465189c 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff @@ -17,7 +17,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/ref_deref.rs:5:6: 5:10 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 - _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 + _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 diff --git a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff index 402a28f3f9f..a58dabdaa41 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff @@ -20,7 +20,7 @@ + // + val: Unevaluated(main, [], Some(promoted[0])) + // mir::Constant + // + span: $DIR/ref_deref.rs:5:6: 5:10 -+ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } ++ // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref[cb9b]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 - StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff index b97d7d1be15..bb265b2af7d 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff @@ -17,7 +17,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/ref_deref_project.rs:5:6: 5:17 - // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff index 48ede27112c..bb7570fabbb 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff @@ -20,7 +20,7 @@ + // + val: Unevaluated(main, [], Some(promoted[0])) + // mir::Constant + // + span: $DIR/ref_deref_project.rs:5:6: 5:17 -+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } ++ // + literal: Const { ty: &(i32, i32), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[e8c3]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 - StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff index 27791852d6d..d5a36182e35 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff @@ -24,7 +24,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 - // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff index 27791852d6d..d5a36182e35 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff @@ -24,7 +24,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 - // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &[u32; 3], val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ slice_len[6547]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _4 = _9; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _3 = _4; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir index 1aabee83be6..5ceefce6114 100644 --- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir @@ -38,7 +38,7 @@ fn bar() -> bool { // + val: Unevaluated(bar, [], Some(promoted[1])) // mir::Constant // + span: $DIR/inline-retag.rs:12:7: 12:9 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[1]) }) } Retag(_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 _4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 Retag(_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 @@ -52,7 +52,7 @@ fn bar() -> bool { // + val: Unevaluated(bar, [], Some(promoted[0])) // mir::Constant // + span: $DIR/inline-retag.rs:12:11: 12:14 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:4 ~ inline_retag[a78c]::bar), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } Retag(_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 _7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 Retag(_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index c1421f20a0b..ba17a45f984 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -4,21 +4,20 @@ fn test() -> Option<Box<u32>> { let mut _0: std::option::Option<std::boxed::Box<u32>>; // return place in scope 0 at $DIR/issue-62289.rs:8:14: 8:30 let mut _1: std::boxed::Box<u32>; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 let mut _2: std::boxed::Box<u32>; // in scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - let mut _3: std::result::Result<u32, std::option::NoneError>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _3: std::ops::ControlFlow<std::option::Option<std::convert::Infallible>, u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 let mut _4: std::option::Option<u32>; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:19 let mut _5: isize; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let _6: std::option::NoneError; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let _6: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 let mut _7: !; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let mut _8: std::option::NoneError; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let mut _9: std::option::NoneError; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - let _10: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + let mut _8: std::option::Option<std::convert::Infallible>; // in scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + let _9: u32; // in scope 0 at $DIR/issue-62289.rs:9:15: 9:20 scope 1 { - debug err => _6; // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20 + debug residual => _6; // in scope 1 at $DIR/issue-62289.rs:9:19: 9:20 scope 2 { } } scope 3 { - debug val => _10; // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20 + debug val => _9; // in scope 3 at $DIR/issue-62289.rs:9:15: 9:20 scope 4 { } } @@ -30,10 +29,10 @@ fn test() -> Option<Box<u32>> { StorageLive(_3); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 StorageLive(_4); // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 _4 = Option::<u32>::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = <Option<u32> as Try>::into_result(move _4) -> [return: bb1, unwind: bb12]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _3 = <Option<u32> as Try>::branch(move _4) -> [return: bb1, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 - // + literal: Const { ty: fn(std::option::Option<u32>) -> std::result::Result<<std::option::Option<u32> as std::ops::Try>::Ok, <std::option::Option<u32> as std::ops::Try>::Error> {<std::option::Option<u32> as std::ops::Try>::into_result}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(std::option::Option<u32>) -> std::ops::ControlFlow<<std::option::Option<u32> as std::ops::Try>::Residual, <std::option::Option<u32> as std::ops::Try>::Output> {<std::option::Option<u32> as std::ops::Try>::branch}, val: Value(Scalar(<ZST>)) } } bb1: { @@ -43,12 +42,12 @@ fn test() -> Option<Box<u32>> { } bb2: { - StorageLive(_10); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 - (*_2) = _10; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20 - StorageDead(_10); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + StorageLive(_9); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _9 = ((_3 as Continue).0: u32); // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + (*_2) = _9; // scope 4 at $DIR/issue-62289.rs:9:15: 9:20 + StorageDead(_9); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 _1 = move _2; // scope 0 at $DIR/issue-62289.rs:9:10: 9:21 - drop(_2) -> [return: bb7, unwind: bb11]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_2) -> [return: bb6, unwind: bb10]; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } bb3: { @@ -57,62 +56,53 @@ fn test() -> Option<Box<u32>> { bb4: { StorageLive(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - _6 = ((_3 as Err).0: std::option::NoneError); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 + _6 = ((_3 as Break).0: std::option::Option<std::convert::Infallible>); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - StorageLive(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _9 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = <NoneError as From<NoneError>>::from(move _9) -> [return: bb5, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _0 = <Option<Box<u32>> as FromResidual<Option<Infallible>>>::from_residual(move _8) -> [return: bb5, unwind: bb11]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:19: 9:20 - // + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {<std::option::NoneError as std::convert::From<std::option::NoneError>>::from}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: fn(std::option::Option<std::convert::Infallible>) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::FromResidual<std::option::Option<std::convert::Infallible>>>::from_residual}, val: Value(Scalar(<ZST>)) } } bb5: { - StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = <Option<Box<u32>> as Try>::from_error(move _8) -> [return: bb6, unwind: bb12]; // scope 2 at $DIR/issue-62289.rs:9:15: 9:20 - // mir::Constant - // + span: $DIR/issue-62289.rs:9:15: 9:20 - // + literal: Const { ty: fn(<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::Error) -> std::option::Option<std::boxed::Box<u32>> {<std::option::Option<std::boxed::Box<u32>> as std::ops::Try>::from_error}, val: Value(Scalar(<ZST>)) } - } - - bb6: { StorageDead(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageDead(_6); // scope 0 at $DIR/issue-62289.rs:9:19: 9:20 - drop(_2) -> bb9; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + drop(_2) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } - bb7: { + bb6: { StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 _0 = Option::<Box<u32>>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 - drop(_1) -> bb8; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + drop(_1) -> bb7; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } - bb8: { + bb7: { StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb9: { + bb8: { StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 StorageDead(_1); // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 StorageDead(_3); // scope 0 at $DIR/issue-62289.rs:10:1: 10:2 - goto -> bb10; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 + goto -> bb9; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb10: { + bb9: { return; // scope 0 at $DIR/issue-62289.rs:10:2: 10:2 } - bb11 (cleanup): { - drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 + bb10 (cleanup): { + drop(_1) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } - bb12 (cleanup): { - drop(_2) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 + bb11 (cleanup): { + drop(_2) -> bb12; // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 } - bb13 (cleanup): { + bb12 (cleanup): { resume; // scope 0 at $DIR/issue-62289.rs:8:1: 10:2 } } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff index 95a8ef997fa..e955feb7d1f 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff @@ -66,7 +66,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _8 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_6.0: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_6.1: &i32) = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff index 95a8ef997fa..e955feb7d1f 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff @@ -66,7 +66,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _8 = _20; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_6.0: &i32) = move _7; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_6.1: &i32) = move _8; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff index 261eb3b27ea..ff8c410a726 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff @@ -87,7 +87,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff index 261eb3b27ea..ff8c410a726 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff @@ -87,7 +87,7 @@ // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:3 ~ issue_73223[2d0f]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _11 = _28; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL diff --git a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff index a37df4da9ae..acb8aca7590 100644 --- a/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff +++ b/src/test/mir-opt/lower_intrinsics.discriminant.LowerIntrinsics.diff @@ -50,7 +50,7 @@ // + val: Unevaluated(discriminant, [T], Some(promoted[2])) // mir::Constant // + span: $DIR/lower_intrinsics.rs:70:42: 70:44 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[2]) }) } _7 = &(*_19); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 _6 = &(*_7); // scope 0 at $DIR/lower_intrinsics.rs:70:42: 70:44 - _5 = discriminant_value::<i32>(move _6) -> bb2; // scope 0 at $DIR/lower_intrinsics.rs:70:5: 70:45 @@ -74,7 +74,7 @@ // + val: Unevaluated(discriminant, [T], Some(promoted[1])) // mir::Constant // + span: $DIR/lower_intrinsics.rs:71:42: 71:45 - // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) } + // + literal: Const { ty: &(), val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[1]) }) } _11 = &(*_18); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 _10 = &(*_11); // scope 0 at $DIR/lower_intrinsics.rs:71:42: 71:45 - _9 = discriminant_value::<()>(move _10) -> bb3; // scope 0 at $DIR/lower_intrinsics.rs:71:5: 71:46 @@ -98,7 +98,7 @@ // + val: Unevaluated(discriminant, [T], Some(promoted[0])) // mir::Constant // + span: $DIR/lower_intrinsics.rs:72:42: 72:47 - // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[8787]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &E, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:27 ~ lower_intrinsics[2872]::discriminant), const_param_did: None }, substs: [T], promoted: Some(promoted[0]) }) } _15 = &(*_17); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 _14 = &(*_15); // scope 0 at $DIR/lower_intrinsics.rs:72:42: 72:47 - _13 = discriminant_value::<E>(move _14) -> bb4; // scope 0 at $DIR/lower_intrinsics.rs:72:5: 72:48 diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir index 5af242376c9..c27ee528b80 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir @@ -57,7 +57,7 @@ fn full_tested_match() -> () { // + val: Unevaluated(full_tested_match, [], Some(promoted[0])) // mir::Constant // + span: $DIR/match_false_edges.rs:16:14: 16:15 - // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &std::option::Option<i32>, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:5 ~ match_false_edges[4011]::full_tested_match), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15 _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27 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 dd8a9251042..80024124dc5 100644 --- a/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff +++ b/src/test/mir-opt/remove_storage_markers.main.RemoveStorageMarkers.diff @@ -32,6 +32,10 @@ scope 5 { debug i => _15; // in scope 5 at $DIR/remove_storage_markers.rs:8:9: 8:10 } + scope 7 (inlined iter::range::<impl Iterator for std::ops::Range<i32>>::next) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 + debug self => _9; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19 + let mut _18: &mut std::ops::Range<i32>; // in scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19 + } } } scope 6 (inlined <std::ops::Range<i32> as IntoIterator>::into_iter) { // at $DIR/remove_storage_markers.rs:8:14: 8:19 @@ -61,19 +65,15 @@ - StorageLive(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 _10 = &mut _4; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 _9 = &mut (*_10); // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 - _8 = <std::ops::Range<i32> as Iterator>::next(move _9) -> bb2; // scope 3 at $DIR/remove_storage_markers.rs:8:14: 8:19 +- StorageLive(_18); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19 + _18 = &mut (*_9); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19 + _8 = <std::ops::Range<i32> as iter::range::RangeIteratorImpl>::spec_next(move _18) -> bb4; // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19 // mir::Constant // + span: $DIR/remove_storage_markers.rs:8:14: 8:19 - // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::Iterator>::Item> {<std::ops::Range<i32> as std::iter::Iterator>::next}, val: Value(Scalar(<ZST>)) } + // + literal: Const { ty: for<'r> fn(&'r mut std::ops::Range<i32>) -> std::option::Option<<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::Item> {<std::ops::Range<i32> as std::iter::range::RangeIteratorImpl>::spec_next}, val: Value(Scalar(<ZST>)) } } bb2: { -- StorageDead(_9); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 - _11 = discriminant(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 - switchInt(move _11) -> [0_isize: bb3, otherwise: bb4]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 - } - - bb3: { _0 = const (); // scope 3 at $DIR/remove_storage_markers.rs:8:5: 10:6 - StorageDead(_10); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 - StorageDead(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 @@ -85,7 +85,7 @@ return; // scope 0 at $DIR/remove_storage_markers.rs:11:2: 11:2 } - bb4: { + bb3: { - StorageLive(_12); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 _12 = ((_8 as Some).0: i32); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 - StorageLive(_13); // scope 4 at $DIR/remove_storage_markers.rs:8:9: 8:10 @@ -111,5 +111,12 @@ - StorageDead(_6); // scope 2 at $DIR/remove_storage_markers.rs:10:5: 10:6 goto -> bb1; // scope 2 at $DIR/remove_storage_markers.rs:8:5: 10:6 } + + bb4: { +- StorageDead(_18); // scope 7 at $DIR/remove_storage_markers.rs:8:14: 8:19 +- StorageDead(_9); // scope 3 at $DIR/remove_storage_markers.rs:8:18: 8:19 + _11 = discriminant(_8); // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 + switchInt(move _11) -> [0_isize: bb2, otherwise: bb3]; // scope 3 at $DIR/remove_storage_markers.rs:8:9: 8:10 + } } 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 c6ef403c3c1..787310d072a 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 @@ -127,7 +127,7 @@ fn array_casts() -> () { // + val: Unevaluated(array_casts, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[317d]::array_casts), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &usize, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:15 ~ retag[13e7]::array_casts), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } Retag(_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _18 = &(*_35); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL Retag(_18); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL 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 4bab5a97488..8abc6a3e4b5 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 @@ -113,7 +113,7 @@ fn main() -> () { StorageLive(_14); // scope 1 at $DIR/retag.rs:40:31: 43:6 _14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:40:31: 43:6 // closure - // + def_id: DefId(0:14 ~ retag[317d]::main::{closure#0}) + // + def_id: DefId(0:14 ~ retag[13e7]::main::{closure#0}) // + substs: [ // i8, // for<'r> extern "rust-call" fn((&'r i32,)) -> &'r i32, @@ -153,7 +153,7 @@ fn main() -> () { // + val: Unevaluated(main, [], Some(promoted[0])) // mir::Constant // + span: $DIR/retag.rs:47:21: 47:23 - // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } + // + literal: Const { ty: &i32, val: Unevaluated(Unevaluated { def: WithOptConstParam { did: DefId(0:13 ~ retag[13e7]::main), const_param_did: None }, substs: [], promoted: Some(promoted[0]) }) } Retag(_28); // scope 7 at $DIR/retag.rs:47:21: 47:23 _23 = &(*_28); // scope 7 at $DIR/retag.rs:47:21: 47:23 Retag(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23 diff --git a/src/test/mir-opt/simplify-arm.rs b/src/test/mir-opt/simplify-arm.rs index 50b5147e0cf..f7dcaa13449 100644 --- a/src/test/mir-opt/simplify-arm.rs +++ b/src/test/mir-opt/simplify-arm.rs @@ -20,8 +20,23 @@ fn id_result(r: Result<u8, i32>) -> Result<u8, i32> { } } +fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> { + r +} + +fn from_error<T, E>(e: E) -> Result<T, E> { + Err(e) +} + +// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure, +// so the relevant desugar is copied inline in order to keep the test testing the same thing. +// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR +// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not. fn id_try(r: Result<u8, i32>) -> Result<u8, i32> { - let x = r?; + let x = match into_result(r) { + Err(e) => return from_error(From::from(e)), + Ok(v) => v, + }; Ok(x) } diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff index ccb3b71817f..a3bad4f0c62 100644 --- a/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyArmIdentity.diff @@ -2,101 +2,93 @@ + // MIR for `id_try` after SimplifyArmIdentity fn id_try(_1: Result<u8, i32>) -> Result<u8, i32> { - debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:23:11: 23:12 - let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:23:34: 23:49 - let _2: u8; // in scope 0 at $DIR/simplify-arm.rs:24:9: 24:10 - let mut _3: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 - let mut _4: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 - let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let _6: i32; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let mut _7: !; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let mut _8: i32; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let mut _9: i32; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let _10: u8; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 - let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:25:8: 25:9 + debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:35:11: 35:12 + let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:35:34: 35:49 + let _2: u8; // in scope 0 at $DIR/simplify-arm.rs:36:9: 36:10 + let mut _3: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + let mut _4: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 + let _6: i32; // in scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 + let mut _7: !; // in scope 0 at $DIR/simplify-arm.rs:37:19: 37:51 + let mut _8: i32; // in scope 0 at $DIR/simplify-arm.rs:37:37: 37:50 + let mut _9: i32; // in scope 0 at $DIR/simplify-arm.rs:37:48: 37:49 + let _10: u8; // in scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 + let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:40:8: 40:9 scope 1 { -- debug x => _2; // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10 -+ debug x => ((_0 as Ok).0: u8); // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10 +- debug x => _2; // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10 ++ debug x => ((_0 as Ok).0: u8); // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10 } scope 2 { -- debug err => _6; // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15 -+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15 - scope 3 { - scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:24:14: 24:15 -- debug t => _9; // in scope 7 at $DIR/simplify-arm.rs:24:14: 24:15 -+ debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify-arm.rs:24:14: 24:15 - } - scope 8 (inlined <Result<u8, i32> as Try>::from_error) { // at $DIR/simplify-arm.rs:24:13: 24:15 -- debug v => _8; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -+ debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 - let mut _12: i32; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 - } +- debug e => _6; // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14 ++ debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14 + scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:37:37: 37:50 +- debug t => _9; // in scope 5 at $DIR/simplify-arm.rs:37:37: 37:50 ++ debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify-arm.rs:37:37: 37:50 } - } - scope 4 { -- debug val => _10; // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15 -+ debug val => ((_0 as Ok).0: u8); // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15 - scope 5 { + scope 6 (inlined from_error::<u8, i32>) { // at $DIR/simplify-arm.rs:37:26: 37:51 +- debug e => _8; // in scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 ++ debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 } } - scope 6 (inlined <Result<u8, i32> as Try>::into_result) { // at $DIR/simplify-arm.rs:24:13: 24:15 - debug self => _4; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + scope 3 { +- debug v => _10; // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13 ++ debug v => ((_0 as Ok).0: u8); // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13 + } + scope 4 (inlined into_result::<u8, i32>) { // at $DIR/simplify-arm.rs:36:19: 36:33 + debug r => _4; // in scope 4 at $DIR/simplify-arm.rs:36:19: 36:33 } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:24:9: 24:10 - StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 - StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 - _4 = _1; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 - _3 = move _4; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 - StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:36:9: 36:10 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + _4 = _1; // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + _3 = move _4; // scope 4 at $DIR/simplify-arm.rs:36:19: 36:33 + StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:36:32: 36:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 + switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 } bb1: { -- StorageLive(_10); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 -- _10 = ((_3 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 -- _2 = _10; // scope 5 at $DIR/simplify-arm.rs:24:13: 24:15 -- StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -+ _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 -- StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 -- _11 = _2; // scope 1 at $DIR/simplify-arm.rs:25:8: 25:9 -- ((_0 as Ok).0: u8) = move _11; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 -- discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 -- StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:25:9: 25:10 - StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 +- StorageLive(_10); // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 +- _10 = ((_3 as Ok).0: u8); // scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 +- _2 = _10; // scope 3 at $DIR/simplify-arm.rs:38:18: 38:19 +- StorageDead(_10); // scope 0 at $DIR/simplify-arm.rs:38:18: 38:19 ++ _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7 +- StorageLive(_11); // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9 +- _11 = _2; // scope 1 at $DIR/simplify-arm.rs:40:8: 40:9 +- ((_0 as Ok).0: u8) = move _11; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 +- discriminant(_0) = 0; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 +- StorageDead(_11); // scope 1 at $DIR/simplify-arm.rs:40:9: 40:10 + StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 + unreachable; // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 } bb3: { -- StorageLive(_6); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -- StorageLive(_8); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 -- StorageLive(_9); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 -- _9 = _6; // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 -- _8 = move _9; // scope 7 at $DIR/simplify-arm.rs:24:14: 24:15 -- StorageDead(_9); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 -- StorageLive(_12); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -- _12 = move _8; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -- ((_0 as Err).0: i32) = move _12; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -- discriminant(_0) = 1; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -- StorageDead(_12); // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -- StorageDead(_8); // scope 3 at $DIR/simplify-arm.rs:24:14: 24:15 -- StorageDead(_6); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -+ _0 = move _3; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 - StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 +- StorageLive(_6); // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 +- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 +- StorageLive(_8); // scope 2 at $DIR/simplify-arm.rs:37:37: 37:50 +- StorageLive(_9); // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49 +- _9 = _6; // scope 2 at $DIR/simplify-arm.rs:37:48: 37:49 +- _8 = move _9; // scope 5 at $DIR/simplify-arm.rs:37:37: 37:50 +- StorageDead(_9); // scope 2 at $DIR/simplify-arm.rs:37:49: 37:50 +- ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 +- discriminant(_0) = 1; // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 +- StorageDead(_8); // scope 2 at $DIR/simplify-arm.rs:37:50: 37:51 +- StorageDead(_6); // scope 0 at $DIR/simplify-arm.rs:37:50: 37:51 ++ _0 = move _3; // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7 + StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2 + goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 + return; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } } diff --git a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff index ec8ac30228e..b6b7511b3f5 100644 --- a/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify_arm.id_try.SimplifyBranchSame.diff @@ -2,75 +2,70 @@ + // MIR for `id_try` after SimplifyBranchSame fn id_try(_1: Result<u8, i32>) -> Result<u8, i32> { - debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:23:11: 23:12 - let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:23:34: 23:49 - let _2: u8; // in scope 0 at $DIR/simplify-arm.rs:24:9: 24:10 - let mut _3: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 - let mut _4: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 - let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let _6: i32; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let mut _7: !; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let mut _8: i32; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let mut _9: i32; // in scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - let _10: u8; // in scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 - let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:25:8: 25:9 + debug r => _1; // in scope 0 at $DIR/simplify-arm.rs:35:11: 35:12 + let mut _0: std::result::Result<u8, i32>; // return place in scope 0 at $DIR/simplify-arm.rs:35:34: 35:49 + let _2: u8; // in scope 0 at $DIR/simplify-arm.rs:36:9: 36:10 + let mut _3: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + let mut _4: std::result::Result<u8, i32>; // in scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + let mut _5: isize; // in scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 + let _6: i32; // in scope 0 at $DIR/simplify-arm.rs:37:13: 37:14 + let mut _7: !; // in scope 0 at $DIR/simplify-arm.rs:37:19: 37:51 + let mut _8: i32; // in scope 0 at $DIR/simplify-arm.rs:37:37: 37:50 + let mut _9: i32; // in scope 0 at $DIR/simplify-arm.rs:37:48: 37:49 + let _10: u8; // in scope 0 at $DIR/simplify-arm.rs:38:12: 38:13 + let mut _11: u8; // in scope 0 at $DIR/simplify-arm.rs:40:8: 40:9 scope 1 { - debug x => ((_0 as Ok).0: u8); // in scope 1 at $DIR/simplify-arm.rs:24:9: 24:10 + debug x => ((_0 as Ok).0: u8); // in scope 1 at $DIR/simplify-arm.rs:36:9: 36:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:24:14: 24:15 - scope 3 { - scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:24:14: 24:15 - debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify-arm.rs:24:14: 24:15 - } - scope 8 (inlined <Result<u8, i32> as Try>::from_error) { // at $DIR/simplify-arm.rs:24:13: 24:15 - debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 - let mut _12: i32; // in scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 - } + debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify-arm.rs:37:13: 37:14 + scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify-arm.rs:37:37: 37:50 + debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify-arm.rs:37:37: 37:50 } - } - scope 4 { - debug val => ((_0 as Ok).0: u8); // in scope 4 at $DIR/simplify-arm.rs:24:13: 24:15 - scope 5 { + scope 6 (inlined from_error::<u8, i32>) { // at $DIR/simplify-arm.rs:37:26: 37:51 + debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 } } - scope 6 (inlined <Result<u8, i32> as Try>::into_result) { // at $DIR/simplify-arm.rs:24:13: 24:15 - debug self => _4; // in scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 + scope 3 { + debug v => ((_0 as Ok).0: u8); // in scope 3 at $DIR/simplify-arm.rs:38:12: 38:13 + } + scope 4 (inlined into_result::<u8, i32>) { // at $DIR/simplify-arm.rs:36:19: 36:33 + debug r => _4; // in scope 4 at $DIR/simplify-arm.rs:36:19: 36:33 } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:24:9: 24:10 - StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 - StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 - _4 = _1; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:14 - _3 = move _4; // scope 6 at $DIR/simplify-arm.rs:24:13: 24:15 - StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 -+ goto -> bb1; // scope 0 at $DIR/simplify-arm.rs:24:14: 24:15 + StorageLive(_2); // scope 0 at $DIR/simplify-arm.rs:36:9: 36:10 + StorageLive(_3); // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 + StorageLive(_4); // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + _4 = _1; // scope 0 at $DIR/simplify-arm.rs:36:31: 36:32 + _3 = move _4; // scope 4 at $DIR/simplify-arm.rs:36:19: 36:33 + StorageDead(_4); // scope 0 at $DIR/simplify-arm.rs:36:32: 36:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 +- switchInt(move _5) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 ++ goto -> bb1; // scope 0 at $DIR/simplify-arm.rs:37:9: 37:15 } bb1: { - _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:25:5: 25:10 - StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 - StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 -- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 -+ goto -> bb2; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 + _0 = move _3; // scope 1 at $DIR/simplify-arm.rs:40:5: 40:10 + StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7 + StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2 +- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 ++ goto -> bb2; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } bb2: { -- unreachable; // scope 0 at $DIR/simplify-arm.rs:24:13: 24:15 +- unreachable; // scope 0 at $DIR/simplify-arm.rs:36:19: 36:33 - } - - bb3: { -- _0 = move _3; // scope 8 at $DIR/simplify-arm.rs:24:13: 24:15 -- StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:24:15: 24:16 -- StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:26:1: 26:2 -- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 +- _0 = move _3; // scope 6 at $DIR/simplify-arm.rs:37:26: 37:51 +- StorageDead(_3); // scope 0 at $DIR/simplify-arm.rs:39:6: 39:7 +- StorageDead(_2); // scope 0 at $DIR/simplify-arm.rs:41:1: 41:2 +- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 - } - - bb4: { - return; // scope 0 at $DIR/simplify-arm.rs:26:2: 26:2 + return; // scope 0 at $DIR/simplify-arm.rs:41:2: 41:2 } } diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs index eb307de2074..15e351e7d50 100644 --- a/src/test/mir-opt/simplify_try.rs +++ b/src/test/mir-opt/simplify_try.rs @@ -4,8 +4,24 @@ // EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir // EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff + +fn into_result<T, E>(r: Result<T, E>) -> Result<T, E> { + r +} + +fn from_error<T, E>(e: E) -> Result<T, E> { + Err(e) +} + +// This was written to the `?` from `try_trait`, but `try_trait_v2` uses a different structure, +// so the relevant desugar is copied inline in order to keep the test testing the same thing. +// FIXME(#85133): while this might be useful for `r#try!`, it would be nice to have a MIR +// optimization that picks up the `?` desugaring, as `SimplifyArmIdentity` does not. fn try_identity(x: Result<u32, i32>) -> Result<u32, i32> { - let y = x?; + let y = match into_result(x) { + Err(e) => return from_error(From::from(e)), + Ok(v) => v, + }; Ok(y) } diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff index b1bae447f9c..e09b8cb39bd 100644 --- a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff +++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff @@ -2,67 +2,62 @@ + // MIR for `try_identity` after DestinationPropagation fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 - let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18 + let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:22:19: 22:51 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 - scope 3 { - scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:8:14: 8:15 - debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 - } - scope 8 (inlined <Result<u32, i32> as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15 - debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - } + debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 + scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50 + debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50 } - } - scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 - scope 5 { + scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51 + debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51 } } - scope 6 (inlined <Result<u32, i32> as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15 -- debug self => _4; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 -+ debug self => _0; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + scope 3 { + debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 + } + scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33 +- debug r => _4; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33 ++ debug r => _0; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33 } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 -- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 -- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 -- _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 -- _3 = move _4; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 -- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 -+ _0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 -+ nop; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 -+ nop; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -+ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:21:9: 21:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 +- _3 = move _4; // scope 4 at $DIR/simplify_try.rs:21:19: 21:33 +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:21:32: 21:33 +- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 ++ nop; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 ++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 ++ nop; // scope 4 at $DIR/simplify_try.rs:21:19: 21:33 ++ nop; // scope 0 at $DIR/simplify_try.rs:21:32: 21:33 ++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 } bb1: { -- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 -- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 -+ nop; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 -+ nop; // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 - return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 +- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 ++ nop; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff index df274852f68..488ad33f80a 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff @@ -2,93 +2,85 @@ + // MIR for `try_identity` after SimplifyArmIdentity fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 - let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18 + let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:22:19: 22:51 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9 scope 1 { -- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 -+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 +- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10 ++ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10 } scope 2 { -- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 -+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 - scope 3 { - scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:8:14: 8:15 -- debug t => _9; // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 -+ debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 - } - scope 8 (inlined <Result<u32, i32> as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15 -- debug v => _8; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 -+ debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - } +- debug e => _6; // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 ++ debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 + scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50 +- debug t => _9; // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50 ++ debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50 } - } - scope 4 { -- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 -+ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 - scope 5 { + scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51 +- debug e => _8; // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51 ++ debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51 } } - scope 6 (inlined <Result<u32, i32> as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15 - debug self => _4; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + scope 3 { +- debug v => _10; // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 ++ debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 + } + scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33 + debug r => _4; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33 } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - _3 = move _4; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _4 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _3 = move _4; // scope 4 at $DIR/simplify_try.rs:21:19: 21:33 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:21:32: 21:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 } bb1: { -- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 -- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 -- _2 = _10; // scope 5 at $DIR/simplify_try.rs:8:13: 8:15 -- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -+ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 -- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 -- _11 = _2; // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 -- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 -- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 -- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:9:9: 9:10 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 - return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 +- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 +- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:23:12: 23:13 +- _2 = _10; // scope 3 at $DIR/simplify_try.rs:23:18: 23:19 +- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:23:18: 23:19 ++ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 +- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:25:8: 25:9 +- _11 = _2; // scope 1 at $DIR/simplify_try.rs:25:8: 25:9 +- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 +- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 +- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:25:9: 25:10 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } bb2: { -- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- _9 = _6; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- _8 = move _9; // scope 7 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageLive(_12); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 -- _12 = move _8; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 -- ((_0 as Err).0: i32) = move _12; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 -- discriminant(_0) = 1; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 -- StorageDead(_12); // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 -- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 -- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 -+ _0 = move _3; // scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 - return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 +- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14 +- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:22:13: 22:14 +- StorageLive(_8); // scope 2 at $DIR/simplify_try.rs:22:37: 22:50 +- StorageLive(_9); // scope 2 at $DIR/simplify_try.rs:22:48: 22:49 +- _9 = _6; // scope 2 at $DIR/simplify_try.rs:22:48: 22:49 +- _8 = move _9; // scope 5 at $DIR/simplify_try.rs:22:37: 22:50 +- StorageDead(_9); // scope 2 at $DIR/simplify_try.rs:22:49: 22:50 +- ((_0 as Err).0: i32) = move _8; // scope 6 at $DIR/simplify_try.rs:22:26: 22:51 +- discriminant(_0) = 1; // scope 6 at $DIR/simplify_try.rs:22:26: 22:51 +- StorageDead(_8); // scope 2 at $DIR/simplify_try.rs:22:50: 22:51 +- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:22:50: 22:51 ++ _0 = move _3; // scope 6 at $DIR/simplify_try.rs:22:26: 22:51 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir index 37274691fb4..5d829f859e9 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir @@ -1,57 +1,52 @@ // MIR for `try_identity` after SimplifyBranchSame fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 - let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18 + let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + let mut _3: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + let mut _4: std::result::Result<u32, i32>; // in scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:22:13: 22:14 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:22:19: 22:51 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:22:37: 22:50 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:22:48: 22:49 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:23:12: 23:13 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:25:8: 25:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 - scope 3 { - scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:8:14: 8:15 - debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 - } - scope 8 (inlined <Result<u32, i32> as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15 - debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - } + debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 + scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50 + debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50 } - } - scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 - scope 5 { + scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51 + debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51 } } - scope 6 (inlined <Result<u32, i32> as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15 - debug self => _4; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + scope 3 { + debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 + } + scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33 + debug r => _4; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33 } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 - StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 - StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - _3 = move _4; // scope 6 at $DIR/simplify_try.rs:8:13: 8:15 - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 - goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:21:9: 21:10 + StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:21:19: 21:33 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _4 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + _3 = move _4; // scope 4 at $DIR/simplify_try.rs:21:19: 21:33 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:21:32: 21:33 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:22:9: 22:15 } bb1: { - _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 - return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 + _0 = move _3; // scope 1 at $DIR/simplify_try.rs:25:5: 25:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:24:6: 24:7 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:26:1: 26:2 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir index f8adcced4b3..1b5232422b6 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir @@ -1,33 +1,29 @@ // MIR for `try_identity` after SimplifyLocals fn try_identity(_1: Result<u32, i32>) -> Result<u32, i32> { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 - let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:20:17: 20:18 + let mut _0: std::result::Result<u32, i32>; // return place in scope 0 at $DIR/simplify_try.rs:20:41: 20:57 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:21:9: 21:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 - scope 3 { - scope 7 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:8:14: 8:15 - debug t => ((_0 as Err).0: i32); // in scope 7 at $DIR/simplify_try.rs:8:14: 8:15 - } - scope 8 (inlined <Result<u32, i32> as Try>::from_error) { // at $DIR/simplify_try.rs:8:13: 8:15 - debug v => ((_0 as Err).0: i32); // in scope 8 at $DIR/simplify_try.rs:8:13: 8:15 - } + debug e => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:22:13: 22:14 + scope 5 (inlined <i32 as From<i32>>::from) { // at $DIR/simplify_try.rs:22:37: 22:50 + debug t => ((_0 as Err).0: i32); // in scope 5 at $DIR/simplify_try.rs:22:37: 22:50 } - } - scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 - scope 5 { + scope 6 (inlined from_error::<u32, i32>) { // at $DIR/simplify_try.rs:22:26: 22:51 + debug e => ((_0 as Err).0: i32); // in scope 6 at $DIR/simplify_try.rs:22:26: 22:51 } } - scope 6 (inlined <Result<u32, i32> as Try>::into_result) { // at $DIR/simplify_try.rs:8:13: 8:15 - debug self => _0; // in scope 6 at $DIR/simplify_try.rs:8:13: 8:15 + scope 3 { + debug v => ((_0 as Ok).0: u32); // in scope 3 at $DIR/simplify_try.rs:23:12: 23:13 + } + scope 4 (inlined into_result::<u32, i32>) { // at $DIR/simplify_try.rs:21:19: 21:33 + debug r => _0; // in scope 4 at $DIR/simplify_try.rs:21:19: 21:33 } bb0: { - _0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 - return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 + _0 = _1; // scope 0 at $DIR/simplify_try.rs:21:31: 21:32 + return; // scope 0 at $DIR/simplify_try.rs:26:2: 26:2 } } diff --git a/src/test/pretty/anonymous-types.rs b/src/test/pretty/anonymous-types.rs new file mode 100644 index 00000000000..5ff452e8e43 --- /dev/null +++ b/src/test/pretty/anonymous-types.rs @@ -0,0 +1,24 @@ +// Test for issue 85480 +// Pretty print anonymous struct and union types + +// pp-exact +// pretty-compare-only + +struct Foo { + _: union { + _: struct { + a: u8, + b: u16, + }, + c: u32, + }, + d: u64, + e: f32, +} + +type A = + struct { + field: u8, + }; + +fn main() { } diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt index 322f5681b3f..dc06a485a8f 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.async2.txt @@ -12,6 +12,7 @@ 12| 1| if b { 13| 1| println!("non_async_func println in block"); 14| 1| } + ^0 15| 1|} 16| | 17| | diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt index 656a2659775..2d8a98a5d0c 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.conditions.txt @@ -5,6 +5,7 @@ 5| 1| if true { 6| 1| countdown = 10; 7| 1| } + ^0 8| | 9| | const B: u32 = 100; 10| 1| let x = if countdown > 7 { @@ -24,6 +25,7 @@ 24| 1| if true { 25| 1| countdown = 10; 26| 1| } + ^0 27| | 28| 1| if countdown > 7 { 29| 1| countdown -= 4; @@ -42,6 +44,7 @@ 41| 1| if true { 42| 1| countdown = 10; 43| 1| } + ^0 44| | 45| 1| if countdown > 7 { 46| 1| countdown -= 4; @@ -54,13 +57,14 @@ 53| | } else { 54| 0| return; 55| | } - 56| | } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal - 57| | // `true` was const-evaluated. The compiler knows the `if` block will be executed. + 56| 0| } + 57| | 58| | 59| 1| let mut countdown = 0; 60| 1| if true { 61| 1| countdown = 1; 62| 1| } + ^0 63| | 64| 1| let z = if countdown > 7 { ^0 diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt index 1b6bb9ff889..7ae0e978808 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.doctest.txt @@ -9,7 +9,7 @@ 8| 1|//! assert_eq!(1, 1); 9| |//! } else { 10| |//! // this is not! - 11| |//! assert_eq!(1, 2); + 11| 0|//! assert_eq!(1, 2); 12| |//! } 13| 1|//! ``` 14| |//! @@ -84,7 +84,7 @@ 74| 1| if true { 75| 1| assert_eq!(1, 1); 76| | } else { - 77| | assert_eq!(1, 2); + 77| 0| assert_eq!(1, 2); 78| | } 79| 1|} 80| | diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt index fab5be41901..fe6a9e93cbf 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.drop_trait.txt @@ -19,11 +19,11 @@ 19| 1| if true { 20| 1| println!("Exiting with error..."); 21| 1| return Err(1); - 22| | } - 23| | - 24| | let _ = Firework { strength: 1000 }; - 25| | - 26| | Ok(()) + 22| 0| } + 23| 0| + 24| 0| let _ = Firework { strength: 1000 }; + 25| 0| + 26| 0| Ok(()) 27| 1|} 28| | 29| |// Expected program output: diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt new file mode 100644 index 00000000000..0fb3808ff2e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generator.txt @@ -0,0 +1,32 @@ + 1| |#![feature(generators, generator_trait)] + 2| | + 3| |use std::ops::{Generator, GeneratorState}; + 4| |use std::pin::Pin; + 5| | + 6| |// The following implementation of a function called from a `yield` statement + 7| |// (apparently requiring the Result and the `String` type or constructor) + 8| |// creates conditions where the `generator::StateTransform` MIR transform will + 9| |// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic + 10| |// to handle this condition, and still report dead block coverage. + 11| 1|fn get_u32(val: bool) -> Result<u32, String> { + 12| 1| if val { Ok(1) } else { Err(String::from("some error")) } + ^0 + 13| 1|} + 14| | + 15| 1|fn main() { + 16| 1| let is_true = std::env::args().len() == 1; + 17| 1| let mut generator = || { + 18| 1| yield get_u32(is_true); + 19| 1| return "foo"; + 20| 1| }; + 21| | + 22| 1| match Pin::new(&mut generator).resume(()) { + 23| 1| GeneratorState::Yielded(Ok(1)) => {} + 24| 0| _ => panic!("unexpected return from resume"), + 25| | } + 26| 1| match Pin::new(&mut generator).resume(()) { + 27| 1| GeneratorState::Complete("foo") => {} + 28| 0| _ => panic!("unexpected return from resume"), + 29| | } + 30| 1|} + diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt index 7b38ffb87cb..8569513e842 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.generics.txt @@ -11,16 +11,16 @@ 11| 3| self.strength = new_strength; 12| 3| } ------------------ - | <generics::Firework<f64>>::set_strength: - | 10| 2| fn set_strength(&mut self, new_strength: T) { - | 11| 2| self.strength = new_strength; - | 12| 2| } - ------------------ | <generics::Firework<i32>>::set_strength: | 10| 1| fn set_strength(&mut self, new_strength: T) { | 11| 1| self.strength = new_strength; | 12| 1| } ------------------ + | <generics::Firework<f64>>::set_strength: + | 10| 2| fn set_strength(&mut self, new_strength: T) { + | 11| 2| self.strength = new_strength; + | 12| 2| } + ------------------ 13| |} 14| | 15| |impl<T> Drop for Firework<T> where T: Copy + std::fmt::Display { @@ -52,15 +52,15 @@ 30| 1| if true { 31| 1| println!("Exiting with error..."); 32| 1| return Err(1); - 33| | } // The remaining lines below have no coverage because `if true` (with the constant literal - 34| | // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`. - 35| | // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown - 36| | // in other tests, the lines below would have coverage (which would show they had `0` - 37| | // executions, assuming the condition still evaluated to `true`). - 38| | - 39| | let _ = Firework { strength: 1000 }; - 40| | - 41| | Ok(()) + 33| 0| } + 34| 0| + 35| 0| + 36| 0| + 37| 0| + 38| 0| + 39| 0| let _ = Firework { strength: 1000 }; + 40| 0| + 41| 0| Ok(()) 42| 1|} 43| | 44| |// Expected program output: diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt index 81d5c7d9034..5d572db7cc6 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.loops_branches.txt @@ -9,23 +9,23 @@ 9| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 10| 1| if true { 11| 1| if false { - 12| | while true { - 13| | } + 12| 0| while true { + 13| 0| } 14| 1| } - 15| 1| write!(f, "error")?; - ^0 - 16| | } else { - 17| | } + 15| 1| write!(f, "cool")?; + ^0 + 16| 0| } else { + 17| 0| } 18| | 19| 10| for i in 0..10 { 20| 10| if true { 21| 10| if false { - 22| | while true {} + 22| 0| while true {} 23| 10| } - 24| 10| write!(f, "error")?; - ^0 - 25| | } else { - 26| | } + 24| 10| write!(f, "cool")?; + ^0 + 25| 0| } else { + 26| 0| } 27| | } 28| 1| Ok(()) 29| 1| } @@ -36,21 +36,21 @@ 34| |impl std::fmt::Display for DisplayTest { 35| 1| fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 36| 1| if false { - 37| | } else { + 37| 0| } else { 38| 1| if false { - 39| | while true {} + 39| 0| while true {} 40| 1| } - 41| 1| write!(f, "error")?; - ^0 + 41| 1| write!(f, "cool")?; + ^0 42| | } 43| 10| for i in 0..10 { 44| 10| if false { - 45| | } else { + 45| 0| } else { 46| 10| if false { - 47| | while true {} + 47| 0| while true {} 48| 10| } - 49| 10| write!(f, "error")?; - ^0 + 49| 10| write!(f, "cool")?; + ^0 50| | } 51| | } 52| 1| Ok(()) diff --git a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt index 5adeef7d085..2d4c57f451a 100644 --- a/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt +++ b/src/test/run-make-fulldeps/coverage-reports/expected_show_coverage.tight_inf_loop.txt @@ -1,6 +1,6 @@ 1| 1|fn main() { 2| 1| if false { - 3| | loop {} + 3| 0| loop {} 4| 1| } 5| 1|} diff --git a/src/test/run-make-fulldeps/coverage/conditions.rs b/src/test/run-make-fulldeps/coverage/conditions.rs index 8a2a0b53e58..057599d1b47 100644 --- a/src/test/run-make-fulldeps/coverage/conditions.rs +++ b/src/test/run-make-fulldeps/coverage/conditions.rs @@ -53,8 +53,8 @@ fn main() { } else { return; } - } // Note: closing brace shows uncovered (vs. `0` for implicit else) because condition literal - // `true` was const-evaluated. The compiler knows the `if` block will be executed. + } + let mut countdown = 0; if true { diff --git a/src/test/run-make-fulldeps/coverage/generator.rs b/src/test/run-make-fulldeps/coverage/generator.rs new file mode 100644 index 00000000000..4319991021e --- /dev/null +++ b/src/test/run-make-fulldeps/coverage/generator.rs @@ -0,0 +1,30 @@ +#![feature(generators, generator_trait)] + +use std::ops::{Generator, GeneratorState}; +use std::pin::Pin; + +// The following implementation of a function called from a `yield` statement +// (apparently requiring the Result and the `String` type or constructor) +// creates conditions where the `generator::StateTransform` MIR transform will +// drop all `Counter` `Coverage` statements from a MIR. `simplify.rs` has logic +// to handle this condition, and still report dead block coverage. +fn get_u32(val: bool) -> Result<u32, String> { + if val { Ok(1) } else { Err(String::from("some error")) } +} + +fn main() { + let is_true = std::env::args().len() == 1; + let mut generator = || { + yield get_u32(is_true); + return "foo"; + }; + + match Pin::new(&mut generator).resume(()) { + GeneratorState::Yielded(Ok(1)) => {} + _ => panic!("unexpected return from resume"), + } + match Pin::new(&mut generator).resume(()) { + GeneratorState::Complete("foo") => {} + _ => panic!("unexpected return from resume"), + } +} diff --git a/src/test/run-make-fulldeps/coverage/generics.rs b/src/test/run-make-fulldeps/coverage/generics.rs index cbeda35d3b8..18b38868496 100644 --- a/src/test/run-make-fulldeps/coverage/generics.rs +++ b/src/test/run-make-fulldeps/coverage/generics.rs @@ -30,11 +30,11 @@ fn main() -> Result<(),u8> { if true { println!("Exiting with error..."); return Err(1); - } // The remaining lines below have no coverage because `if true` (with the constant literal - // `true`) is guaranteed to execute the `then` block, which is also guaranteed to `return`. - // Thankfully, in the normal case, conditions are not guaranteed ahead of time, and as shown - // in other tests, the lines below would have coverage (which would show they had `0` - // executions, assuming the condition still evaluated to `true`). + } + + + + let _ = Firework { strength: 1000 }; diff --git a/src/test/run-make-fulldeps/coverage/loops_branches.rs b/src/test/run-make-fulldeps/coverage/loops_branches.rs index 4d9bbad3367..7116ce47f4b 100644 --- a/src/test/run-make-fulldeps/coverage/loops_branches.rs +++ b/src/test/run-make-fulldeps/coverage/loops_branches.rs @@ -12,7 +12,7 @@ impl std::fmt::Debug for DebugTest { while true { } } - write!(f, "error")?; + write!(f, "cool")?; } else { } @@ -21,7 +21,7 @@ impl std::fmt::Debug for DebugTest { if false { while true {} } - write!(f, "error")?; + write!(f, "cool")?; } else { } } @@ -38,7 +38,7 @@ impl std::fmt::Display for DisplayTest { if false { while true {} } - write!(f, "error")?; + write!(f, "cool")?; } for i in 0..10 { if false { @@ -46,7 +46,7 @@ impl std::fmt::Display for DisplayTest { if false { while true {} } - write!(f, "error")?; + write!(f, "cool")?; } } Ok(()) diff --git a/src/test/run-make-fulldeps/issue-47551/Makefile b/src/test/run-make-fulldeps/issue-47551/Makefile new file mode 100644 index 00000000000..f4495e6b671 --- /dev/null +++ b/src/test/run-make-fulldeps/issue-47551/Makefile @@ -0,0 +1,9 @@ +# only-linux +# ignore-32bit + +-include ../tools.mk + +all: + $(RUSTC) eh_frame-terminator.rs + $(call RUN,eh_frame-terminator) | $(CGREP) '1122334455667788' + objdump --dwarf=frames $(TMPDIR)/eh_frame-terminator | $(CGREP) 'ZERO terminator' 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 new file mode 100644 index 00000000000..2f740dc4fac --- /dev/null +++ b/src/test/run-make-fulldeps/issue-47551/eh_frame-terminator.rs @@ -0,0 +1,23 @@ +// run-pass + +#![feature(backtrace)] +#[derive(Clone, Copy)] +struct Foo { + array: [u64; 10240], +} + +impl Foo { + const fn new() -> Self { + Self { + array: [0x1122_3344_5566_7788; 10240] + } + } +} + +static BAR: [Foo; 10240] = [Foo::new(); 10240]; + +fn main() { + let bt = std::backtrace::Backtrace::force_capture(); + println!("Hello, world! {:?}", bt); + println!("{:x}", BAR[0].array[0]); +} diff --git a/src/test/run-make-fulldeps/link-dedup/Makefile b/src/test/run-make-fulldeps/link-dedup/Makefile new file mode 100644 index 00000000000..4e7ce0f02d4 --- /dev/null +++ b/src/test/run-make-fulldeps/link-dedup/Makefile @@ -0,0 +1,12 @@ +# ignore-msvc + +-include ../tools.mk + +all: + $(RUSTC) depa.rs + $(RUSTC) depb.rs + $(RUSTC) depc.rs + $(RUSTC) empty.rs --cfg bar 2>&1 | $(CGREP) '"-ltesta" "-ltestb" "-ltesta"' + $(RUSTC) empty.rs 2>&1 | $(CGREP) '"-ltesta"' + $(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltestb"' + $(RUSTC) empty.rs 2>&1 | $(CGREP) -v '"-ltesta" "-ltesta"' diff --git a/src/test/run-make-fulldeps/link-dedup/depa.rs b/src/test/run-make-fulldeps/link-dedup/depa.rs new file mode 100644 index 00000000000..e48ffd6413c --- /dev/null +++ b/src/test/run-make-fulldeps/link-dedup/depa.rs @@ -0,0 +1,7 @@ +#![crate_type = "rlib"] + +#[link(name = "testa")] +extern "C" {} + +#[link(name = "testa")] +extern "C" {} diff --git a/src/test/run-make-fulldeps/link-dedup/depb.rs b/src/test/run-make-fulldeps/link-dedup/depb.rs new file mode 100644 index 00000000000..b1be21fe005 --- /dev/null +++ b/src/test/run-make-fulldeps/link-dedup/depb.rs @@ -0,0 +1,8 @@ +#![feature(link_cfg)] +#![crate_type = "rlib"] + +#[link(name = "testb", cfg(foo))] +extern "C" {} + +#[link(name = "testb", cfg(bar))] +extern "C" {} diff --git a/src/test/run-make-fulldeps/link-dedup/depc.rs b/src/test/run-make-fulldeps/link-dedup/depc.rs new file mode 100644 index 00000000000..8dcb3dee5a2 --- /dev/null +++ b/src/test/run-make-fulldeps/link-dedup/depc.rs @@ -0,0 +1,4 @@ +#![crate_type = "rlib"] + +#[link(name = "testa")] +extern "C" {} diff --git a/src/test/run-make-fulldeps/link-dedup/empty.rs b/src/test/run-make-fulldeps/link-dedup/empty.rs new file mode 100644 index 00000000000..e00ae18f4af --- /dev/null +++ b/src/test/run-make-fulldeps/link-dedup/empty.rs @@ -0,0 +1,5 @@ +extern crate depa; +extern crate depb; +extern crate depc; + +fn main() {} diff --git a/src/test/run-make-fulldeps/print-unversioned-files/Makefile b/src/test/run-make-fulldeps/print-unversioned-files/Makefile deleted file mode 100644 index e368f61cddf..00000000000 --- a/src/test/run-make-fulldeps/print-unversioned-files/Makefile +++ /dev/null @@ -1,4 +0,0 @@ --include ../tools.mk - -all: - $(RUSTDOC) -Z unstable-options --print unversioned-files | sort | diff - unversioned-files.txt diff --git a/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt b/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt deleted file mode 100644 index 4b20cd5d745..00000000000 --- a/src/test/run-make-fulldeps/print-unversioned-files/unversioned-files.txt +++ /dev/null @@ -1,16 +0,0 @@ -COPYRIGHT.txt -FiraSans-LICENSE.txt -FiraSans-Medium.woff -FiraSans-Medium.woff2 -FiraSans-Regular.woff -FiraSans-Regular.woff2 -LICENSE-APACHE.txt -LICENSE-MIT.txt -SourceCodePro-It.ttf.woff -SourceCodePro-LICENSE.txt -SourceCodePro-Regular.ttf.woff -SourceCodePro-Semibold.ttf.woff -SourceSerif4-Bold.ttf.woff -SourceSerif4-It.ttf.woff -SourceSerif4-LICENSE.md -SourceSerif4-Regular.ttf.woff diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile new file mode 100644 index 00000000000..6d0bc4186f2 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/Makefile @@ -0,0 +1,9 @@ +include ../tools.mk + +# Test that rustdoc will properly canonicalize the target spec json path just like rustc + +OUTPUT_DIR := "$(TMPDIR)/rustdoc-target-spec-json-path" + +all: + $(RUSTC) --crate-type lib dummy_core.rs --target target.json + $(RUSTDOC) -o $(OUTPUT_DIR) -L $(TMPDIR) my_crate.rs --target target.json diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs new file mode 100644 index 00000000000..da27b7f3463 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/dummy_core.rs @@ -0,0 +1,2 @@ +#![feature(no_core)] +#![no_core] diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs new file mode 100644 index 00000000000..12aa0822084 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/my_crate.rs @@ -0,0 +1,3 @@ +#![feature(no_core)] +#![no_core] +extern crate dummy_core; diff --git a/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json new file mode 100644 index 00000000000..58e924a9895 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-target-spec-json-path/target.json @@ -0,0 +1,39 @@ +{ + "arch": "x86_64", + "cpu": "x86-64", + "crt-static-respected": true, + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", + "dynamic-linking": true, + "env": "gnu", + "executables": true, + "has-elf-tls": true, + "has-rpath": true, + "is-builtin": true, + "linker-is-gnu": true, + "llvm-target": "x86_64-unknown-linux-gnu", + "max-atomic-width": 64, + "os": "linux", + "position-independent-executables": true, + "pre-link-args": { + "gcc": [ + "-m64" + ] + }, + "relro-level": "full", + "stack-probes": { + "kind": "inline-or-call", + "min-llvm-version-for-inline": [ + 11, + 0, + 1 + ] + }, + "supported-sanitizers": [ + "address", + "leak", + "memory", + "thread" + ], + "target-family": "unix", + "target-pointer-width": "64" +} diff --git a/src/test/run-make/emit-named-files/Makefile b/src/test/run-make/emit-named-files/Makefile new file mode 100644 index 00000000000..03eb83b97e3 --- /dev/null +++ b/src/test/run-make/emit-named-files/Makefile @@ -0,0 +1,33 @@ +-include ../../run-make-fulldeps/tools.mk + +OUT=$(TMPDIR)/emit + +all: asm llvm-bc llvm-ir obj metadata link dep-info mir + +asm: $(OUT) + $(RUSTC) --emit asm=$(OUT)/libfoo.s foo.rs + test -f $(OUT)/libfoo.s +llvm-bc: $(OUT) + $(RUSTC) --emit llvm-bc=$(OUT)/libfoo.bc foo.rs + test -f $(OUT)/libfoo.bc +llvm-ir: $(OUT) + $(RUSTC) --emit llvm-ir=$(OUT)/libfoo.ll foo.rs + test -f $(OUT)/libfoo.ll +obj: $(OUT) + $(RUSTC) --emit obj=$(OUT)/libfoo.o foo.rs + test -f $(OUT)/libfoo.o +metadata: $(OUT) + $(RUSTC) --emit metadata=$(OUT)/libfoo.rmeta foo.rs + test -f $(OUT)/libfoo.rmeta +link: $(OUT) + $(RUSTC) --emit link=$(OUT)/libfoo.rlib foo.rs + test -f $(OUT)/libfoo.rlib +dep-info: $(OUT) + $(RUSTC) --emit dep-info=$(OUT)/libfoo.d foo.rs + test -f $(OUT)/libfoo.d +mir: $(OUT) + $(RUSTC) --emit mir=$(OUT)/libfoo.mir foo.rs + test -f $(OUT)/libfoo.mir + +$(OUT): + mkdir -p $(OUT) diff --git a/src/test/run-make/emit-named-files/foo.rs b/src/test/run-make/emit-named-files/foo.rs new file mode 100644 index 00000000000..c1bfaa6cab5 --- /dev/null +++ b/src/test/run-make/emit-named-files/foo.rs @@ -0,0 +1 @@ +#![crate_type = "rlib"] diff --git a/src/test/run-make/incremental-session-fail/Makefile b/src/test/run-make/incremental-session-fail/Makefile new file mode 100644 index 00000000000..0461bb926e7 --- /dev/null +++ b/src/test/run-make/incremental-session-fail/Makefile @@ -0,0 +1,14 @@ +include ../../run-make-fulldeps/tools.mk + +SESSION_DIR := $(TMPDIR)/session +OUTPUT_FILE := $(TMPDIR)/build-output + +all: + echo $(TMPDIR) + # Make it so that rustc will fail to create a session directory. + touch $(SESSION_DIR) + # Check exit code is 1 for an error, and not 101 for ICE. + $(RUSTC) foo.rs --crate-type=rlib -C incremental=$(SESSION_DIR) > $(OUTPUT_FILE) 2>&1; [ $$? -eq 1 ] + $(CGREP) "Could not create incremental compilation crate directory" < $(OUTPUT_FILE) + # -v tests are fragile, hopefully this text won't change + $(CGREP) -v "internal compiler error" < $(OUTPUT_FILE) diff --git a/src/test/run-make/incremental-session-fail/foo.rs b/src/test/run-make/incremental-session-fail/foo.rs new file mode 100644 index 00000000000..d11c69f812a --- /dev/null +++ b/src/test/run-make/incremental-session-fail/foo.rs @@ -0,0 +1 @@ +// intentionally empty diff --git a/src/test/run-make/unstable-flag-required/Makefile b/src/test/run-make/unstable-flag-required/Makefile index b8769d5f690..aa20d6aa4bf 100644 --- a/src/test/run-make/unstable-flag-required/Makefile +++ b/src/test/run-make/unstable-flag-required/Makefile @@ -2,3 +2,4 @@ all: $(RUSTDOC) --output-format=json x.html 2>&1 | diff - output-format-json.stderr + $(RUSTC) --force-warns dead_code x.rs 2>&1 | diff - force-warns.stderr diff --git a/src/test/run-make/unstable-flag-required/force-warns.stderr b/src/test/run-make/unstable-flag-required/force-warns.stderr new file mode 100644 index 00000000000..e0936196a11 --- /dev/null +++ b/src/test/run-make/unstable-flag-required/force-warns.stderr @@ -0,0 +1,2 @@ +error: the `-Z unstable-options` flag must also be passed to enable the flag `--force-warns=lints` + diff --git a/src/test/rustdoc-gui/escape-key.goml b/src/test/rustdoc-gui/escape-key.goml new file mode 100644 index 00000000000..ec034f52c97 --- /dev/null +++ b/src/test/rustdoc-gui/escape-key.goml @@ -0,0 +1,34 @@ +goto: file://|DOC_PATH|/test_docs/index.html +// First, we check that the search results are hidden when the Escape key is pressed. +write: (".search-input", "test") +wait-for: "#search > h1" // The search element is empty before the first search +assert: ("#search", "class", "content") +assert: ("#main", "class", "content hidden") +press-key: "Escape" +assert: ("#search", "class", "content hidden") +assert: ("#main", "class", "content") + +// Check that focusing the search input brings back the search results +focus: ".search-input" +assert: ("#search", "class", "content") +assert: ("#main", "class", "content hidden") + +// Now let's check that when the help popup is displayed and we press Escape, it doesn't +// hide the search results too. +click: "#help-button" +assert: ("#help", "class", "") +press-key: "Escape" +assert: ("#help", "class", "hidden") +assert: ("#search", "class", "content") +assert: ("#main", "class", "content hidden") + +// Check that Escape hides the search results when a search result is focused. +focus: ".search-input" +assert: ".search-input:focus" +press-key: "ArrowDown" +assert-false: ".search-input:focus" +assert: "#results a:focus" +press-key: "Escape" +assert: ("#help", "class", "hidden") +assert: ("#search", "class", "content hidden") +assert: ("#main", "class", "content") diff --git a/src/test/rustdoc-gui/search-result-colors.goml b/src/test/rustdoc-gui/search-result-colors.goml new file mode 100644 index 00000000000..25a01512159 --- /dev/null +++ b/src/test/rustdoc-gui/search-result-colors.goml @@ -0,0 +1,14 @@ +goto: file://|DOC_PATH|/test_docs/index.html +// We set the theme so we're sure that the corect values will be used, whatever the computer +// this test is running on. +local-storage: {"rustdoc-theme": "dark", "rustdoc-preferred-dark-theme": "dark", "rustdoc-use-system-theme": "false"} +// If the text isn't displayed, the browser doesn't compute color style correctly... +show-text: true +// We reload the page so the local storage settings are being used. +reload: +write: (".search-input", "thisisanalias") +// Waiting for the search results to appear... +wait-for: "#titles" +// Checking that the colors for the alias element are the ones expected. +assert: (".result-name > .alias", {"color": "rgb(255, 255, 255)"}) +assert: (".result-name > .alias > .grey", {"color": "rgb(204, 204, 204)"}) diff --git a/src/test/rustdoc-gui/search-result-display.goml b/src/test/rustdoc-gui/search-result-display.goml new file mode 100644 index 00000000000..96d15c624f1 --- /dev/null +++ b/src/test/rustdoc-gui/search-result-display.goml @@ -0,0 +1,12 @@ +goto: file://|DOC_PATH|/test_docs/index.html +size: (900, 1000) +write: (".search-input", "test") +// Waiting for the search results to appear... +wait-for: "#titles" +// The width is returned by "getComputedStyle" which returns the exact number instead of the +// CSS rule which is "50%"... +assert: (".search-results div.desc", {"width": "320px"}) +size: (600, 100) +// As counter-intuitive as it may seem, in this width, the width is "100%", which is why +// when computed it's larger. +assert: (".search-results div.desc", {"width": "570px"}) diff --git a/src/test/rustdoc-gui/search-result-keyword.goml b/src/test/rustdoc-gui/search-result-keyword.goml new file mode 100644 index 00000000000..e7612d66371 --- /dev/null +++ b/src/test/rustdoc-gui/search-result-keyword.goml @@ -0,0 +1,10 @@ +goto: file://|DOC_PATH|/test_docs/index.html +write: (".search-input", "CookieMonster") +// Waiting for the search results to appear... +wait-for: "#titles" +// Note: The two next assert commands could be merged as one but readability would be +// less good. +// +// Checking that the CSS is displaying " (keyword)" in italic. +assert: (".result-name span.keyword > i", "(keyword)") +assert: (".result-name span.keyword", "CookieMonster (keyword)") diff --git a/src/test/rustdoc-gui/sidebar.goml b/src/test/rustdoc-gui/sidebar.goml new file mode 100644 index 00000000000..388ca120d77 --- /dev/null +++ b/src/test/rustdoc-gui/sidebar.goml @@ -0,0 +1,56 @@ +goto: file://|DOC_PATH|/test_docs/index.html +assert: (".sidebar > .location", "Crate test_docs") +// In modules, we only have one "location" element. +assert: (".sidebar .location", 1) +assert: (".sidebar-elems > #all-types", "See all test_docs's items") +// We check that we have the crates list and that the "current" on is "test_docs". +assert: (".sidebar-elems > .crate > ul > li > a.current", "test_docs") +// And we're also supposed to have the list of items in the current module. +assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules") +assert: (".sidebar-elems > .items > ul > li:nth-child(2)", "Structs") +assert: (".sidebar-elems > .items > ul > li:nth-child(3)", "Enums") +assert: (".sidebar-elems > .items > ul > li:nth-child(4)", "Traits") +assert: (".sidebar-elems > .items > ul > li:nth-child(5)", "Functions") +assert: (".sidebar-elems > .items > ul > li:nth-child(6)", "Keywords") +assert: ("#structs + table td > a", "Foo") +click: "#structs + table td > a" + +// PAGE: struct.Foo.html +assert: (".sidebar .location", 2) +// We check that there is no crate listed outside of the top level. +assert-false: ".sidebar-elems > .crate" +// We now go back to the crate page to click on the "lib2" crate link. +goto: file://|DOC_PATH|/test_docs/index.html +click: ".sidebar-elems > .crate > ul > li:first-child > a" + +// PAGE: lib2/index.html +goto: file://|DOC_PATH|/lib2/index.html +assert: (".sidebar > .location", "Crate lib2") +// We check that we have the crates list and that the "current" on is now "lib2". +assert: (".sidebar-elems > .crate > ul > li > a.current", "lib2") +// We now go to the "foobar" function page. +assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Modules") +assert: (".sidebar-elems > .items > ul > li:nth-child(2)", "Functions") +assert: ("#functions + table td > a", "foobar") +click: "#functions + table td > a" + +// PAGE: fn.foobar.html +// In items containing no items (like functions or constants) and in modules, we have one +// "location" elements. +assert: (".sidebar .location", 1) +// There is a "<br>" tag between "in" and "lib2", but it doesn't count as a space. +assert: (".sidebar .sidebar-elems .location", "Other items inlib2") +// We check that we don't have the crate list. +assert-false: ".sidebar-elems > .crate" + +goto: ./module/index.html +assert: (".sidebar > .location", "Module module") +// We check that we don't have the crate list. +assert-false: ".sidebar-elems > .crate" + +goto: ./sub_module/sub_sub_module/index.html +assert: (".sidebar > .location", "Module sub_sub_module") +// We check that we don't have the crate list. +assert-false: ".sidebar-elems > .crate" +assert: (".sidebar-elems > .items > ul > li:nth-child(1)", "Functions") +assert: ("#functions + table td > a", "foo") diff --git a/src/test/rustdoc-gui/src/lib.rs b/src/test/rustdoc-gui/src/lib.rs index eeba3e3f907..272b1d05452 100644 --- a/src/test/rustdoc-gui/src/lib.rs +++ b/src/test/rustdoc-gui/src/lib.rs @@ -2,6 +2,7 @@ //! documentation generated so we can test each different features. #![crate_name = "test_docs"] +#![feature(doc_keyword)] use std::fmt; @@ -35,6 +36,7 @@ impl Foo { } /// Just a normal enum. +#[doc(alias = "ThisIsAnAlias")] pub enum WhoLetTheDogOut { /// Woof! Woof, @@ -91,3 +93,6 @@ pub fn check_list_code_block() {} pub enum AnEnum { WithVariants { and: usize, sub: usize, variants: usize }, } + +#[doc(keyword = "CookieMonster")] +pub mod keyword {} diff --git a/src/test/rustdoc-gui/src/lib2.rs b/src/test/rustdoc-gui/src/lib2.rs new file mode 100644 index 00000000000..73384cbf906 --- /dev/null +++ b/src/test/rustdoc-gui/src/lib2.rs @@ -0,0 +1,11 @@ +pub mod module { + pub mod sub_module { + pub mod sub_sub_module { + pub fn foo() {} + } + pub fn bar() {} + } + pub fn whatever() {} +} + +pub fn foobar() {} diff --git a/src/test/rustdoc-ui/ignore-block-help.rs b/src/test/rustdoc-ui/ignore-block-help.rs index c22dddd11df..86f6a2868fb 100644 --- a/src/test/rustdoc-ui/ignore-block-help.rs +++ b/src/test/rustdoc-ui/ignore-block-help.rs @@ -3,5 +3,8 @@ /// ```ignore (to-prevent-tidy-error) /// let heart = '❤️'; /// ``` -//~^^^ WARN +//~^^^ WARNING could not parse code block +//~| NOTE on by default +//~| NOTE character literal may only contain one codepoint +//~| HELP `ignore` code blocks require valid Rust code pub struct X; diff --git a/src/test/rustdoc-ui/ignore-block-help.stderr b/src/test/rustdoc-ui/ignore-block-help.stderr index d45cd92d2d1..9c02ff11d19 100644 --- a/src/test/rustdoc-ui/ignore-block-help.stderr +++ b/src/test/rustdoc-ui/ignore-block-help.stderr @@ -7,11 +7,13 @@ LL | | /// let heart = '❤️'; LL | | /// ``` | |_______^ | - = note: error from rustc: character literal may only contain one codepoint -help: `ignore` code blocks require valid Rust code for syntax highlighting. Mark blocks that do not contain Rust code as text + = note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default +help: `ignore` code blocks require valid Rust code for syntax highlighting; mark blocks that do not contain Rust code as text: ```text + --> $DIR/ignore-block-help.rs:3:5 | -LL | /// ```text,ignore (to-prevent-tidy-error) - | ^^^^^^^^ +LL | /// ```ignore (to-prevent-tidy-error) + | ^^^ + = note: error from rustc: character literal may only contain one codepoint warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/invalid-syntax.rs b/src/test/rustdoc-ui/invalid-syntax.rs index c395a8ef3d4..b503d1093fd 100644 --- a/src/test/rustdoc-ui/invalid-syntax.rs +++ b/src/test/rustdoc-ui/invalid-syntax.rs @@ -71,7 +71,7 @@ pub fn blargh() {} /// \_ #[doc = "```"] pub fn crazy_attrs() {} -//~^^^^ WARNING doc comment contains an invalid Rust code block +//~^^^^ WARNING could not parse code block /// ```rust /// ``` diff --git a/src/test/rustdoc-ui/invalid-syntax.stderr b/src/test/rustdoc-ui/invalid-syntax.stderr index 75acdc5ab5f..82eac9bd68b 100644 --- a/src/test/rustdoc-ui/invalid-syntax.stderr +++ b/src/test/rustdoc-ui/invalid-syntax.stderr @@ -7,6 +7,7 @@ LL | | /// \__________pkt->size___________/ \_result->size_/ \__pkt->si LL | | /// ``` | |_______^ | + = note: `#[warn(rustdoc::invalid_rust_codeblocks)]` on by default = note: error from rustc: unknown start of token: \ = note: error from rustc: unknown start of token: \ = note: error from rustc: unknown start of token: \ @@ -90,7 +91,7 @@ LL | | /// ``` | = note: error from rustc: unknown start of token: \ -warning: doc comment contains an invalid Rust code block +warning: could not parse code block as Rust code --> $DIR/invalid-syntax.rs:70:1 | LL | / #[doc = "```"] diff --git a/src/test/rustdoc/assoc-consts.rs b/src/test/rustdoc/assoc-consts.rs index 7bfa922185b..a3dd166e651 100644 --- a/src/test/rustdoc/assoc-consts.rs +++ b/src/test/rustdoc/assoc-consts.rs @@ -88,14 +88,12 @@ impl Qux for Bar { /// Docs for QUX1 in impl. const QUX1: i8 = 5; // @has - '//*[@id="associatedconstant.QUX_DEFAULT0"]' 'const QUX_DEFAULT0: u16' - // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait." - // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait." + // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT12 in trait." const QUX_DEFAULT0: u16 = 6; // @has - '//*[@id="associatedconstant.QUX_DEFAULT1"]' 'const QUX_DEFAULT1: i16' // @has - '//*[@class="docblock"]' "Docs for QUX_DEFAULT1 in impl." /// Docs for QUX_DEFAULT1 in impl. const QUX_DEFAULT1: i16 = 7; // @has - '//*[@id="associatedconstant.QUX_DEFAULT2"]' 'const QUX_DEFAULT2: u32' - // @!has - '//div[@class="impl-items"]/details[@open=""]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait." - // @has - '//div[@class="impl-items"]/details//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait." + // @has - '//div[@class="impl-items"]//*[@class="docblock"]' "Docs for QUX_DEFAULT2 in trait." } diff --git a/src/test/rustdoc/async-fn.rs b/src/test/rustdoc/async-fn.rs index 4b66b5271c5..9f95d9a994b 100644 --- a/src/test/rustdoc/async-fn.rs +++ b/src/test/rustdoc/async-fn.rs @@ -77,12 +77,12 @@ struct AsyncFdReadyGuard<'a, T> { x: &'a T } impl Foo { // @has async_fn/struct.Foo.html - // @has - '//h4[@class="method"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>' + // @has - '//div[@class="method has-srclink"]' 'pub async fn complicated_lifetimes( &self, context: &impl Bar) -> impl Iterator<Item = &usize>' pub async fn complicated_lifetimes(&self, context: &impl Bar) -> impl Iterator<Item = &usize> {} // taken from `tokio` as an example of a method that was particularly bad before - // @has - '//h4[@class="method"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>" + // @has - '//div[@class="method has-srclink"]' "pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()>" pub async fn readable<T>(&self) -> Result<AsyncFdReadyGuard<'_, T>, ()> {} - // @has - '//h4[@class="method"]' "pub async fn mut_self(&mut self)" + // @has - '//div[@class="method has-srclink"]' "pub async fn mut_self(&mut self)" pub async fn mut_self(&mut self) {} } diff --git a/src/test/rustdoc/auto_aliases.rs b/src/test/rustdoc/auto_aliases.rs index 56e0770ab5c..01ea09a9461 100644 --- a/src/test/rustdoc/auto_aliases.rs +++ b/src/test/rustdoc/auto_aliases.rs @@ -1,6 +1,6 @@ #![feature(auto_traits)] -// @has auto_aliases/trait.Bar.html '//h3[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo' +// @has auto_aliases/trait.Bar.html '//div[@data-aliases="auto_aliases::Foo"]' 'impl Bar for Foo' pub struct Foo; pub auto trait Bar {} diff --git a/src/test/rustdoc/blanket-reexport-item.rs b/src/test/rustdoc/blanket-reexport-item.rs index f247ee637b9..6f0c15cb5ac 100644 --- a/src/test/rustdoc/blanket-reexport-item.rs +++ b/src/test/rustdoc/blanket-reexport-item.rs @@ -1,6 +1,6 @@ #![crate_name = "foo"] -// @has foo/struct.S.html '//h3[@id="impl-Into%3CU%3E"]//code' 'impl<T, U> Into<U> for T' +// @has foo/struct.S.html '//div[@id="impl-Into%3CU%3E"]//code' 'impl<T, U> Into<U> for T' pub struct S2 {} mod m { pub struct S {} diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs index fb5c8517f6c..2761f92ef57 100644 --- a/src/test/rustdoc/const-display.rs +++ b/src/test/rustdoc/const-display.rs @@ -38,12 +38,12 @@ pub const unsafe fn bar_not_gated() -> u32 { 42 } pub struct Foo; impl Foo { - // @has 'foo/struct.Foo.html' '//h4[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32' + // @has 'foo/struct.Foo.html' '//div[@id="method.gated"]/code' 'pub unsafe fn gated() -> u32' #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_unstable(feature="foo", issue = "none")] pub const unsafe fn gated() -> u32 { 42 } - // @has 'foo/struct.Foo.html' '//h4[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32' + // @has 'foo/struct.Foo.html' '//div[@id="method.stable_impl"]/code' 'pub const fn stable_impl() -> u32' // @has - '//span[@class="since"]' '1.0.0 (const: 1.2.0)' #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.2.0")] diff --git a/src/test/rustdoc/const-fn.rs b/src/test/rustdoc/const-fn.rs index 9ea7343e075..28eba849ace 100644 --- a/src/test/rustdoc/const-fn.rs +++ b/src/test/rustdoc/const-fn.rs @@ -8,7 +8,7 @@ pub const fn bar() -> usize { } // @has foo/struct.Foo.html -// @has - '//*[@class="method"]' 'const fn new()' +// @has - '//*[@class="method has-srclink"]' 'const fn new()' pub struct Foo(usize); impl Foo { diff --git a/src/test/rustdoc/const-generics/add-impl.rs b/src/test/rustdoc/const-generics/add-impl.rs index 77432ba1539..8f412aa8c40 100644 --- a/src/test/rustdoc/const-generics/add-impl.rs +++ b/src/test/rustdoc/const-generics/add-impl.rs @@ -8,7 +8,7 @@ pub struct Simd<T, const WIDTH: usize> { inner: T, } -// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//h3/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>' +// @has foo/struct.Simd.html '//div[@id="trait-implementations-list"]//div/code' 'impl Add<Simd<u8, 16_usize>> for Simd<u8, 16>' impl Add for Simd<u8, 16> { type Output = Self; diff --git a/src/test/rustdoc/const-generics/const-generic-slice.rs b/src/test/rustdoc/const-generics/const-generic-slice.rs index 60d96770f7e..626a9e2b210 100644 --- a/src/test/rustdoc/const-generics/const-generic-slice.rs +++ b/src/test/rustdoc/const-generics/const-generic-slice.rs @@ -6,7 +6,7 @@ pub trait Array { } // @has foo/trait.Array.html -// @has - '//h3[@class="impl"]' 'impl<T, const N: usize> Array for [T; N]' +// @has - '//div[@class="impl has-srclink"]' 'impl<T, const N: usize> Array for [T; N]' impl <T, const N: usize> Array for [T; N] { type Item = T; } diff --git a/src/test/rustdoc/const-generics/const-generics-docs.rs b/src/test/rustdoc/const-generics/const-generics-docs.rs index 21bf216c304..7c4c70432c7 100644 --- a/src/test/rustdoc/const-generics/const-generics-docs.rs +++ b/src/test/rustdoc/const-generics/const-generics-docs.rs @@ -36,7 +36,7 @@ pub struct Foo<const N: usize> where u8: Trait<N>; // @has foo/struct.Bar.html '//pre[@class="rust struct"]' 'pub struct Bar<T, const N: usize>(_)' pub struct Bar<T, const N: usize>([T; N]); -// @has foo/struct.Foo.html '//h3[@id="impl"]/code' 'impl<const M: usize> Foo<M> where u8: Trait<M>' +// @has foo/struct.Foo.html '//div[@id="impl"]/code' 'impl<const M: usize> Foo<M> where u8: Trait<M>' impl<const M: usize> Foo<M> where u8: Trait<M> { // @has - '//*[@id="associatedconstant.FOO_ASSOC"]' 'pub const FOO_ASSOC: usize' pub const FOO_ASSOC: usize = M + 13; @@ -47,7 +47,7 @@ impl<const M: usize> Foo<M> where u8: Trait<M> { } } -// @has foo/struct.Bar.html '//h3[@id="impl"]/code' 'impl<const M: usize> Bar<u8, M>' +// @has foo/struct.Bar.html '//div[@id="impl"]/code' 'impl<const M: usize> Bar<u8, M>' impl<const M: usize> Bar<u8, M> { // @has - '//*[@id="method.hey"]' \ // 'pub fn hey<const N: usize>(&self) -> Foo<N> where u8: Trait<N>' diff --git a/src/test/rustdoc/const-generics/const-impl.rs b/src/test/rustdoc/const-generics/const-impl.rs index 04fb3395333..e4e504dd83b 100644 --- a/src/test/rustdoc/const-generics/const-impl.rs +++ b/src/test/rustdoc/const-generics/const-impl.rs @@ -9,20 +9,20 @@ pub enum Order { } // @has foo/struct.VSet.html '//pre[@class="rust struct"]' 'pub struct VSet<T, const ORDER: Order>' -// @has foo/struct.VSet.html '//h3[@id="impl-Send"]/code' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>' -// @has foo/struct.VSet.html '//h3[@id="impl-Sync"]/code' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>' +// @has foo/struct.VSet.html '//div[@id="impl-Send"]/code' 'impl<T, const ORDER: Order> Send for VSet<T, ORDER>' +// @has foo/struct.VSet.html '//div[@id="impl-Sync"]/code' 'impl<T, const ORDER: Order> Sync for VSet<T, ORDER>' pub struct VSet<T, const ORDER: Order> { inner: Vec<T>, } -// @has foo/struct.VSet.html '//h3[@id="impl"]/code' 'impl<T> VSet<T, {Order::Sorted}>' +// @has foo/struct.VSet.html '//div[@id="impl"]/code' 'impl<T> VSet<T, {Order::Sorted}>' impl <T> VSet<T, {Order::Sorted}> { pub fn new() -> Self { Self { inner: Vec::new() } } } -// @has foo/struct.VSet.html '//h3[@id="impl-1"]/code' 'impl<T> VSet<T, {Order::Unsorted}>' +// @has foo/struct.VSet.html '//div[@id="impl-1"]/code' 'impl<T> VSet<T, {Order::Unsorted}>' impl <T> VSet<T, {Order::Unsorted}> { pub fn new() -> Self { Self { inner: Vec::new() } @@ -31,7 +31,7 @@ impl <T> VSet<T, {Order::Unsorted}> { pub struct Escape<const S: &'static str>; -// @has foo/struct.Escape.html '//h3[@id="impl"]/code' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>' +// @has foo/struct.Escape.html '//div[@id="impl"]/code' 'impl Escape<{ r#"<script>alert("Escape");</script>"# }>' impl Escape<{ r#"<script>alert("Escape");</script>"# }> { pub fn f() {} } diff --git a/src/test/rustdoc/doc-assoc-item.rs b/src/test/rustdoc/doc-assoc-item.rs index 4d5c9f83e1e..4f15418650c 100644 --- a/src/test/rustdoc/doc-assoc-item.rs +++ b/src/test/rustdoc/doc-assoc-item.rs @@ -8,7 +8,7 @@ pub trait Bar { fn foo(foo: Self::Fuu); } -// @has doc_assoc_item/struct.Foo.html '//*[@class="impl"]' 'impl<T: Bar<Fuu = u32>> Foo<T>' +// @has doc_assoc_item/struct.Foo.html '//*[@class="impl has-srclink"]' 'impl<T: Bar<Fuu = u32>> Foo<T>' impl<T: Bar<Fuu = u32>> Foo<T> { pub fn new(t: T) -> Foo<T> { Foo { diff --git a/src/test/rustdoc/duplicate_impls/issue-33054.rs b/src/test/rustdoc/duplicate_impls/issue-33054.rs index 1e644bb9739..15c3444606c 100644 --- a/src/test/rustdoc/duplicate_impls/issue-33054.rs +++ b/src/test/rustdoc/duplicate_impls/issue-33054.rs @@ -1,8 +1,8 @@ // @has issue_33054/impls/struct.Foo.html // @has - '//code' 'impl Foo' // @has - '//code' 'impl Bar for Foo' -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 -// @count - '//*[@id="main"]/details/summary/*[@class="impl"]' 1 +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 +// @count - '//*[@id="main"]/details/summary/*[@class="impl has-srclink"]' 1 // @has issue_33054/impls/bar/trait.Bar.html // @has - '//code' 'impl Bar for Foo' // @count - '//*[@class="struct"]' 1 diff --git a/src/test/rustdoc/empty-impls.rs b/src/test/rustdoc/empty-impls.rs index 86dec32e625..2eed1cc9d74 100644 --- a/src/test/rustdoc/empty-impls.rs +++ b/src/test/rustdoc/empty-impls.rs @@ -1,19 +1,19 @@ #![crate_name = "foo"] // @has foo/struct.Foo.html -// @has - '//div[@id="synthetic-implementations-list"]/h3[@id="impl-Send"]' 'impl Send for Foo' +// @has - '//div[@id="synthetic-implementations-list"]/div[@id="impl-Send"]' 'impl Send for Foo' pub struct Foo; pub trait EmptyTrait {} -// @has - '//div[@id="trait-implementations-list"]/h3[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo' +// @has - '//div[@id="trait-implementations-list"]/div[@id="impl-EmptyTrait"]' 'impl EmptyTrait for Foo' impl EmptyTrait for Foo {} pub trait NotEmpty { fn foo(&self); } -// @has - '//div[@id="trait-implementations-list"]/details/summary/h3[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo' +// @has - '//div[@id="trait-implementations-list"]/details/summary/div[@id="impl-NotEmpty"]' 'impl NotEmpty for Foo' impl NotEmpty for Foo { fn foo(&self) {} } diff --git a/src/test/rustdoc/ensure-src-link.rs b/src/test/rustdoc/ensure-src-link.rs index b7e7b11d27a..4b6270b26da 100644 --- a/src/test/rustdoc/ensure-src-link.rs +++ b/src/test/rustdoc/ensure-src-link.rs @@ -2,5 +2,5 @@ // This test ensures that the [src] link is present on traits items. -// @has foo/trait.Iterator.html '//h3[@id="method.zip"]/a[@class="srclink"]' "[src]" +// @has foo/trait.Iterator.html '//div[@id="method.zip"]/a[@class="srclink"]' "[src]" pub use std::iter::Iterator; diff --git a/src/test/rustdoc/external-doc.rs b/src/test/rustdoc/external-doc.rs index befd31a5492..0dadca551a9 100644 --- a/src/test/rustdoc/external-doc.rs +++ b/src/test/rustdoc/external-doc.rs @@ -1,5 +1,4 @@ #![feature(external_doc)] -#![feature(extended_key_value_attributes)] // @has external_doc/struct.CanHasDocs.html // @has - '//h1' 'External Docs' diff --git a/src/test/rustdoc/generic-impl.rs b/src/test/rustdoc/generic-impl.rs index 03a4d197499..96ced021041 100644 --- a/src/test/rustdoc/generic-impl.rs +++ b/src/test/rustdoc/generic-impl.rs @@ -2,10 +2,10 @@ use std::fmt; -// @!has foo/struct.Bar.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T' +// @!has foo/struct.Bar.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T' pub struct Bar; -// @has foo/struct.Foo.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T' +// @has foo/struct.Foo.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T' pub struct Foo; // @has foo/struct.Foo.html '//div[@class="sidebar-links"]/a[@href="#impl-ToString"]' 'ToString' diff --git a/src/test/rustdoc/impl-parts.rs b/src/test/rustdoc/impl-parts.rs index 90110babea7..e4039eecb71 100644 --- a/src/test/rustdoc/impl-parts.rs +++ b/src/test/rustdoc/impl-parts.rs @@ -5,7 +5,7 @@ pub auto trait AnAutoTrait {} pub struct Foo<T> { field: T } -// @has impl_parts/struct.Foo.html '//*[@class="impl"]//code' \ +// @has impl_parts/struct.Foo.html '//*[@class="impl has-srclink"]//code' \ // "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync," // @has impl_parts/trait.AnAutoTrait.html '//*[@class="item-list"]//code' \ // "impl<T: Clone> !AnAutoTrait for Foo<T> where T: Sync," diff --git a/src/test/rustdoc/inline_cross/assoc-items.rs b/src/test/rustdoc/inline_cross/assoc-items.rs index 8fc01c3f04c..231805a52b9 100644 --- a/src/test/rustdoc/inline_cross/assoc-items.rs +++ b/src/test/rustdoc/inline_cross/assoc-items.rs @@ -16,18 +16,15 @@ extern crate assoc_items; // @has - '//*[@id="associatedconstant.ConstNoDefault"]' 'const ConstNoDefault: i16' // @has - '//*[@class="docblock"]' 'dox for ConstNoDefault' // @has - '//*[@id="associatedconstant.ConstWithDefault"]' 'const ConstWithDefault: u16' -// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for ConstWithDefault' -// @has - '//details/details/div[@class="docblock"]' 'docs for ConstWithDefault' +// @has - '//div[@class="docblock"]' 'docs for ConstWithDefault' // @has - '//*[@id="associatedtype.TypeNoDefault"]' 'type TypeNoDefault = i32' // @has - '//*[@class="docblock"]' 'dox for TypeNoDefault' // @has - '//*[@id="associatedtype.TypeWithDefault"]' 'type TypeWithDefault = u32' -// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for TypeWithDefault' -// @has - '//details/details/div[@class="docblock"]' 'docs for TypeWithDefault' +// @has - '//div[@class="docblock"]' 'docs for TypeWithDefault' // @has - '//*[@id="method.method_no_default"]' 'fn method_no_default()' // @has - '//*[@class="docblock"]' 'dox for method_no_default' // @has - '//*[@id="method.method_with_default"]' 'fn method_with_default()' -// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for method_with_default' -// @has - '//details/details/div[@class="docblock"]' 'docs for method_with_default' +// @has - '//div[@class="docblock"]' 'docs for method_with_default' pub use assoc_items::MyStruct; // @has foo/trait.MyTrait.html diff --git a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs index cc0596c70ce..9b67022fd4b 100644 --- a/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs +++ b/src/test/rustdoc/inline_cross/impl-inline-without-trait.rs @@ -8,6 +8,5 @@ extern crate impl_inline_without_trait; // @has 'foo/struct.MyStruct.html' // @has - '//*[@id="method.my_trait_method"]' 'fn my_trait_method()' -// @!has - '//details[@open=""]/details/div[@class="docblock"]' 'docs for my_trait_method' -// @has - '//details/details/div[@class="docblock"]' 'docs for my_trait_method' +// @has - '//div[@class="docblock"]' 'docs for my_trait_method' pub use impl_inline_without_trait::MyStruct; diff --git a/src/test/rustdoc/inline_cross/issue-31948-1.rs b/src/test/rustdoc/inline_cross/issue-31948-1.rs index f47056223fe..390f0b845e0 100644 --- a/src/test/rustdoc/inline_cross/issue-31948-1.rs +++ b/src/test/rustdoc/inline_cross/issue-31948-1.rs @@ -5,8 +5,8 @@ extern crate rustdoc_nonreachable_impls; // @has issue_31948_1/struct.Wobble.html -// @has - '//*[@class="impl"]//code' 'Bark for' -// @has - '//*[@class="impl"]//code' 'Woof for' +// @has - '//*[@class="impl has-srclink"]//code' 'Bark for' +// @has - '//*[@class="impl has-srclink"]//code' 'Woof for' // @!has - '//*[@class="impl"]//code' 'Bar for' // @!has - '//*[@class="impl"]//code' 'Qux for' pub use rustdoc_nonreachable_impls::hidden::Wobble; diff --git a/src/test/rustdoc/inline_cross/issue-31948-2.rs b/src/test/rustdoc/inline_cross/issue-31948-2.rs index 282f0679e98..013e777440f 100644 --- a/src/test/rustdoc/inline_cross/issue-31948-2.rs +++ b/src/test/rustdoc/inline_cross/issue-31948-2.rs @@ -5,9 +5,9 @@ extern crate rustdoc_nonreachable_impls; // @has issue_31948_2/struct.Wobble.html -// @has - '//*[@class="impl"]//code' 'Qux for' -// @has - '//*[@class="impl"]//code' 'Bark for' -// @has - '//*[@class="impl"]//code' 'Woof for' +// @has - '//*[@class="impl has-srclink"]//code' 'Qux for' +// @has - '//*[@class="impl has-srclink"]//code' 'Bark for' +// @has - '//*[@class="impl has-srclink"]//code' 'Woof for' // @!has - '//*[@class="impl"]//code' 'Bar for' pub use rustdoc_nonreachable_impls::hidden::Wobble; diff --git a/src/test/rustdoc/inline_cross/issue-31948.rs b/src/test/rustdoc/inline_cross/issue-31948.rs index d5725175e3f..82dcc2d2cc3 100644 --- a/src/test/rustdoc/inline_cross/issue-31948.rs +++ b/src/test/rustdoc/inline_cross/issue-31948.rs @@ -5,9 +5,9 @@ extern crate rustdoc_nonreachable_impls; // @has issue_31948/struct.Foo.html -// @has - '//*[@class="impl"]//code' 'Bark for' -// @has - '//*[@class="impl"]//code' 'Woof for' -// @!has - '//*[@class="impl"]//code' 'Bar for' +// @has - '//*[@class="impl has-srclink"]//code' 'Bark for' +// @has - '//*[@class="impl has-srclink"]//code' 'Woof for' +// @!has - '//*[@class="impl has-srclink"]//code' 'Bar for' // @!has - '//*[@class="impl"]//code' 'Qux for' pub use rustdoc_nonreachable_impls::Foo; diff --git a/src/test/rustdoc/issue-21474.rs b/src/test/rustdoc/issue-21474.rs index 5de26abace6..43ce13fd9b1 100644 --- a/src/test/rustdoc/issue-21474.rs +++ b/src/test/rustdoc/issue-21474.rs @@ -7,5 +7,5 @@ mod inner { pub trait Blah { } // @count issue_21474/struct.What.html \ -// '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 +// '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 pub struct What; diff --git a/src/test/rustdoc/issue-29503.rs b/src/test/rustdoc/issue-29503.rs index 2b25da77d7e..23d9e73b567 100644 --- a/src/test/rustdoc/issue-29503.rs +++ b/src/test/rustdoc/issue-29503.rs @@ -5,7 +5,7 @@ pub trait MyTrait { fn my_string(&self) -> String; } -// @has - "//div[@id='implementors-list']//h3[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug" +// @has - "//div[@id='implementors-list']//div[@id='impl-MyTrait']//code" "impl<T> MyTrait for T where T: Debug" impl<T> MyTrait for T where T: fmt::Debug { fn my_string(&self) -> String { format!("{:?}", self) diff --git a/src/test/rustdoc/issue-33302.rs b/src/test/rustdoc/issue-33302.rs index 21356b513ee..1777744c0fc 100644 --- a/src/test/rustdoc/issue-33302.rs +++ b/src/test/rustdoc/issue-33302.rs @@ -23,7 +23,7 @@ macro_rules! make { } // @has issue_33302/struct.S.html \ - // '//h3[@class="impl"]' 'impl T<[i32; 16]> for S' + // '//div[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S' // @has - '//*[@id="associatedconstant.C"]' 'const C: [i32; 16]' // @has - '//*[@id="associatedconstant.D"]' 'const D: i32' impl T<[i32; ($n * $n)]> for S { @@ -31,7 +31,7 @@ macro_rules! make { } // @has issue_33302/struct.S.html \ - // '//h3[@class="impl"]' 'impl T<[i32; 16]> for S' + // '//div[@class="impl has-srclink"]' 'impl T<[i32; 16]> for S' // @has - '//*[@id="associatedconstant.C-1"]' 'const C: (i32,)' // @has - '//*[@id="associatedconstant.D-1"]' 'const D: i32' impl T<(i32,)> for S { @@ -39,7 +39,7 @@ macro_rules! make { } // @has issue_33302/struct.S.html \ - // '//h3[@class="impl"]' 'impl T<(i32, i32)> for S' + // '//div[@class="impl has-srclink"]' 'impl T<(i32, i32)> for S' // @has - '//*[@id="associatedconstant.C-2"]' 'const C: (i32, i32)' // @has - '//*[@id="associatedconstant.D-2"]' 'const D: i32' impl T<(i32, i32)> for S { diff --git a/src/test/rustdoc/issue-45584.rs b/src/test/rustdoc/issue-45584.rs index 8a5f0413826..86479e6fb2e 100644 --- a/src/test/rustdoc/issue-45584.rs +++ b/src/test/rustdoc/issue-45584.rs @@ -4,12 +4,12 @@ pub trait Bar<T, U> {} // @has 'foo/struct.Foo1.html' pub struct Foo1; -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 -// @has - '//*[@class="impl"]' "impl Bar<Foo1, &'static Foo1> for Foo1" +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 +// @has - '//*[@class="impl has-srclink"]' "impl Bar<Foo1, &'static Foo1> for Foo1" impl Bar<Foo1, &'static Foo1> for Foo1 {} // @has 'foo/struct.Foo2.html' pub struct Foo2; -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 -// @has - '//*[@class="impl"]' "impl Bar<&'static Foo2, Foo2> for u8" +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 +// @has - '//*[@class="impl has-srclink"]' "impl Bar<&'static Foo2, Foo2> for u8" impl Bar<&'static Foo2, Foo2> for u8 {} diff --git a/src/test/rustdoc/issue-50159.rs b/src/test/rustdoc/issue-50159.rs index 0820512e521..69774aa351f 100644 --- a/src/test/rustdoc/issue-50159.rs +++ b/src/test/rustdoc/issue-50159.rs @@ -14,7 +14,7 @@ impl<B, C> Signal2 for B where B: Signal<Item = C> { // @has - '//code' 'impl<B> Send for Switch<B> where <B as Signal>::Item: Send' // @has - '//code' 'impl<B> Sync for Switch<B> where <B as Signal>::Item: Sync' // @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5 pub struct Switch<B: Signal> { pub inner: <B as Signal2>::Item2, } diff --git a/src/test/rustdoc/issue-51236.rs b/src/test/rustdoc/issue-51236.rs index d018c948162..e01dae6c7f1 100644 --- a/src/test/rustdoc/issue-51236.rs +++ b/src/test/rustdoc/issue-51236.rs @@ -7,8 +7,8 @@ pub mod traits { } // @has issue_51236/struct.Owned.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \ -// Owned<T> where <T as Owned<'static>>::Reader: Send" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<T> Send for Owned<T> where <T as Owned<'static>>::Reader: Send" pub struct Owned<T> where T: for<'a> ::traits::Owned<'a> { marker: PhantomData<<T as ::traits::Owned<'static>>::Reader>, } diff --git a/src/test/rustdoc/issue-53812.rs b/src/test/rustdoc/issue-53812.rs index ddc14e68675..0b1f2f2c93f 100644 --- a/src/test/rustdoc/issue-53812.rs +++ b/src/test/rustdoc/issue-53812.rs @@ -12,9 +12,10 @@ macro_rules! array_impls { } } -// @has issue_53812/trait.MyIterator.html '//*[@id="implementors-list"]/h3[1]' 'MyStruct<[T; 0]>' -// @has - '//*[@id="implementors-list"]/h3[2]' 'MyStruct<[T; 1]>' -// @has - '//*[@id="implementors-list"]/h3[3]' 'MyStruct<[T; 2]>' -// @has - '//*[@id="implementors-list"]/h3[4]' 'MyStruct<[T; 3]>' -// @has - '//*[@id="implementors-list"]/h3[5]' 'MyStruct<[T; 10]>' +// @has issue_53812/trait.MyIterator.html +// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][1]' 'MyStruct<[T; 0]>' +// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][2]' 'MyStruct<[T; 1]>' +// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][3]' 'MyStruct<[T; 2]>' +// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][4]' 'MyStruct<[T; 3]>' +// @has - '//*[@id="implementors-list"]/div[@class="impl has-srclink"][5]' 'MyStruct<[T; 10]>' array_impls! { 10 3 2 1 0 } diff --git a/src/test/rustdoc/issue-54705.rs b/src/test/rustdoc/issue-54705.rs index 47da94a4ccf..5a94d36ed70 100644 --- a/src/test/rustdoc/issue-54705.rs +++ b/src/test/rustdoc/issue-54705.rs @@ -3,11 +3,11 @@ pub trait ScopeHandle<'scope> {} // @has issue_54705/struct.ScopeFutureContents.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \ -// Send for ScopeFutureContents<'scope, S> where S: Sync" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<'scope, S> Send for ScopeFutureContents<'scope, S> where S: Sync" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'scope, S> \ -// Sync for ScopeFutureContents<'scope, S> where S: Sync" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<'scope, S> Sync for ScopeFutureContents<'scope, S> where S: Sync" pub struct ScopeFutureContents<'scope, S> where S: ScopeHandle<'scope>, { diff --git a/src/test/rustdoc/issue-55321.rs b/src/test/rustdoc/issue-55321.rs index d1877f39ba7..b664733487b 100644 --- a/src/test/rustdoc/issue-55321.rs +++ b/src/test/rustdoc/issue-55321.rs @@ -1,16 +1,18 @@ #![feature(negative_impls)] // @has issue_55321/struct.A.html -// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Send for A" -// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' "impl !Sync for A" +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl !Send for A" +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl !Sync for A" pub struct A(); impl !Send for A {} impl !Sync for A {} // @has issue_55321/struct.B.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \ -// B<T>" -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \ -// B<T>" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<T> !Send for B<T>" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<T> !Sync for B<T>" pub struct B<T: ?Sized>(A, Box<T>); diff --git a/src/test/rustdoc/issue-56822.rs b/src/test/rustdoc/issue-56822.rs index b932a3d3474..977596e0b90 100644 --- a/src/test/rustdoc/issue-56822.rs +++ b/src/test/rustdoc/issue-56822.rs @@ -17,8 +17,8 @@ impl<'a, T> MyTrait for Inner<'a, T> { } // @has issue_56822/struct.Parser.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a> Send for \ -// Parser<'a>" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<'a> Send for Parser<'a>" pub struct Parser<'a> { field: <Wrapper<Inner<'a, u8>> as MyTrait>::Output } diff --git a/src/test/rustdoc/issue-60726.rs b/src/test/rustdoc/issue-60726.rs index 79b8b70c545..e0417f1a4f4 100644 --- a/src/test/rustdoc/issue-60726.rs +++ b/src/test/rustdoc/issue-60726.rs @@ -26,10 +26,10 @@ where {} // @has issue_60726/struct.IntoIter.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \ -// IntoIter<T>" -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Sync for \ -// IntoIter<T>" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<T> !Send for IntoIter<T>" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<T> !Sync for IntoIter<T>" pub struct IntoIter<T>{ hello:DynTrait<FooInterface<T>>, } diff --git a/src/test/rustdoc/issue-76501.rs b/src/test/rustdoc/issue-76501.rs index d468f35e280..a90e0fea092 100644 --- a/src/test/rustdoc/issue-76501.rs +++ b/src/test/rustdoc/issue-76501.rs @@ -8,7 +8,8 @@ pub const fn bloop() -> i32 { pub struct Struct {} impl Struct { - // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' 'pub const fn blurp() -> i32' + // @has 'issue_76501/struct.Struct.html' '//*[@class="method has-srclink"]' \ + // 'pub const fn blurp() -> i32' /// A useless function that always returns 1. pub const fn blurp() -> i32 { 1 diff --git a/src/test/rustdoc/issue-78673.rs b/src/test/rustdoc/issue-78673.rs index d09141c3204..2e4bec2544c 100644 --- a/src/test/rustdoc/issue-78673.rs +++ b/src/test/rustdoc/issue-78673.rs @@ -7,8 +7,8 @@ pub trait AnAmazingTrait {} impl<T: Something> AnAmazingTrait for T {} // @has 'issue_78673/struct.MyStruct.html' -// @has - '//*[@class="impl"]' 'AnAmazingTrait for MyStruct' -// @!has - '//*[@class="impl"]' 'AnAmazingTrait for T' +// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for MyStruct' +// @!has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T' pub struct MyStruct; impl AnAmazingTrait for MyStruct {} @@ -16,8 +16,8 @@ impl AnAmazingTrait for MyStruct {} // generic structs may have _both_ specific and blanket impls that apply // @has 'issue_78673/struct.AnotherStruct.html' -// @has - '//*[@class="impl"]' 'AnAmazingTrait for AnotherStruct<()>' -// @has - '//*[@class="impl"]' 'AnAmazingTrait for T' +// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for AnotherStruct<()>' +// @has - '//*[@class="impl has-srclink"]' 'AnAmazingTrait for T' pub struct AnotherStruct<T>(T); impl<T: Something> Something for AnotherStruct<T> {} diff --git a/src/test/rustdoc/issue-85454.rs b/src/test/rustdoc/issue-85454.rs new file mode 100644 index 00000000000..45664dfc382 --- /dev/null +++ b/src/test/rustdoc/issue-85454.rs @@ -0,0 +1,17 @@ +// @has issue_85454/trait.FromResidual.html +// @has - '//pre[@class="rust trait"]' 'pub trait FromResidual<R = <Self as Try>::Residual> { fn from_residual(residual: R) -> Self; }' +pub trait FromResidual<R = <Self as Try>::Residual> { + fn from_residual(residual: R) -> Self; +} + +pub trait Try: FromResidual { + type Output; + type Residual; + fn from_output(output: Self::Output) -> Self; + fn branch(self) -> ControlFlow<Self::Residual, Self::Output>; +} + +pub enum ControlFlow<B, C = ()> { + Continue(C), + Break(B), +} diff --git a/src/test/rustdoc/keyword.rs b/src/test/rustdoc/keyword.rs index 25e8b7912e7..652517c5c90 100644 --- a/src/test/rustdoc/keyword.rs +++ b/src/test/rustdoc/keyword.rs @@ -4,7 +4,8 @@ // @has foo/index.html '//h2[@id="keywords"]' 'Keywords' // @has foo/index.html '//a[@href="keyword.match.html"]' 'match' -// @has foo/index.html '//div[@class="block items"]//a/@href' '#keywords' +// @has foo/index.html '//div[@class="sidebar-elems"]//li/a' 'Keywords' +// @has foo/index.html '//div[@class="sidebar-elems"]//li/a/@href' '#keywords' // @has foo/keyword.match.html '//a[@class="keyword"]' 'match' // @has foo/keyword.match.html '//span[@class="in-band"]' 'Keyword match' // @has foo/keyword.match.html '//section[@id="main"]//div[@class="docblock"]//p' 'this is a test!' diff --git a/src/test/rustdoc/manual_impl.rs b/src/test/rustdoc/manual_impl.rs index 776a191ceef..b2ee077bc6b 100644 --- a/src/test/rustdoc/manual_impl.rs +++ b/src/test/rustdoc/manual_impl.rs @@ -24,13 +24,10 @@ pub trait T { // @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait implementation.' // @has - '//*[@class="docblock"]' 'Docs associated with the S1 trait a_method implementation.' // @!has - '//*[@class="docblock"]' 'Docs associated with the trait a_method definition.' -// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.' -// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.' -// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.' -// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait c_method definition.' +// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.' +// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait c_method definition.' // @!has - '//*[@class="docblock"]' 'There is another line' -// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Read more' -// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Read more' +// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Read more' pub struct S1(usize); /// Docs associated with the S1 trait implementation. @@ -45,10 +42,7 @@ impl T for S1 { // @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait implementation.' // @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait a_method implementation.' // @has - '//*[@class="docblock"]' 'Docs associated with the S2 trait c_method implementation.' -// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait a_method definition.' -// @!has - '//details[open=""]/div[@class="docblock"]' 'Docs associated with the trait c_method definition.' -// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.' -// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait b_method definition.' +// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait b_method definition.' pub struct S2(usize); /// Docs associated with the S2 trait implementation. @@ -65,10 +59,9 @@ impl T for S2 { } // @has manual_impl/struct.S3.html '//*[@class="trait"]' 'T' -// @has - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait implementation.' -// @has - '//details[@open=""]/div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.' -// @!has - '//div[@class="impl-items"]/details[@open=""]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.' -// @has - '//div[@class="impl-items"]/details//div[@class="docblock"]' 'Docs associated with the trait a_method definition.' +// @has - '//div[@class="docblock"]' 'Docs associated with the S3 trait implementation.' +// @has - '//div[@class="docblock"]' 'Docs associated with the S3 trait b_method implementation.' +// @has - '//div[@class="impl-items"]//div[@class="docblock"]' 'Docs associated with the trait a_method definition.' pub struct S3(usize); /// Docs associated with the S3 trait implementation. diff --git a/src/test/rustdoc/mut-params.rs b/src/test/rustdoc/mut-params.rs index 1ef7e304fa2..f3ea6995839 100644 --- a/src/test/rustdoc/mut-params.rs +++ b/src/test/rustdoc/mut-params.rs @@ -5,7 +5,7 @@ pub struct Foo; -// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method"]' 2 +// @count foo/struct.Foo.html '//*[@class="impl-items"]//*[@class="method has-srclink"]' 2 // @!has - '//*[@class="impl-items"]//*[@class="method"]' 'mut' impl Foo { pub fn foo(mut self) {} diff --git a/src/test/rustdoc/negative-impl.rs b/src/test/rustdoc/negative-impl.rs index d76aac6906c..ee65a7d5f39 100644 --- a/src/test/rustdoc/negative-impl.rs +++ b/src/test/rustdoc/negative-impl.rs @@ -5,8 +5,10 @@ pub struct Alpha; // @matches negative_impl/struct.Bravo.html '//pre' "pub struct Bravo<B>" pub struct Bravo<B>(B); -// @matches negative_impl/struct.Alpha.html '//*[@class="impl"]//code' "impl !Send for Alpha" +// @matches negative_impl/struct.Alpha.html '//*[@class="impl has-srclink"]//code' \ +// "impl !Send for Alpha" impl !Send for Alpha {} -// @matches negative_impl/struct.Bravo.html '//*[@class="impl"]//code' "impl<B> !Send for Bravo<B>" +// @matches negative_impl/struct.Bravo.html '//*[@class="impl has-srclink"]//code' "\ +// impl<B> !Send for Bravo<B>" impl<B> !Send for Bravo<B> {} diff --git a/src/test/rustdoc/primitive-generic-impl.rs b/src/test/rustdoc/primitive-generic-impl.rs index 5794322ba1d..2951f5128e0 100644 --- a/src/test/rustdoc/primitive-generic-impl.rs +++ b/src/test/rustdoc/primitive-generic-impl.rs @@ -2,4 +2,4 @@ include!("primitive/primitive-generic-impl.rs"); -// @has foo/primitive.i32.html '//h3[@id="impl-ToString"]//code' 'impl<T> ToString for T' +// @has foo/primitive.i32.html '//div[@id="impl-ToString"]//code' 'impl<T> ToString for T' diff --git a/src/test/rustdoc/pub-method.rs b/src/test/rustdoc/pub-method.rs index 8e88b2b5901..fa7de0aff6a 100644 --- a/src/test/rustdoc/pub-method.rs +++ b/src/test/rustdoc/pub-method.rs @@ -10,8 +10,8 @@ pub fn bar() -> usize { } // @has foo/struct.Foo.html -// @has - '//*[@class="method"]' 'pub fn new()' -// @has - '//*[@class="method"]' 'fn not_pub()' +// @has - '//*[@class="method has-srclink"]' 'pub fn new()' +// @has - '//*[@class="method has-srclink"]' 'fn not_pub()' pub struct Foo(usize); impl Foo { diff --git a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs index 6219a2c3b90..d256fbe8de0 100644 --- a/src/test/rustdoc/sidebar-links-to-foreign-impl.rs +++ b/src/test/rustdoc/sidebar-links-to-foreign-impl.rs @@ -6,9 +6,9 @@ // @has - '//*[@class="sidebar-title"][@href="#foreign-impls"]' 'Implementations on Foreign Types' // @has - '//h2[@id="foreign-impls"]' 'Implementations on Foreign Types' // @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-u32"]' 'u32' -// @has - '//h3[@id="impl-Foo-for-u32"]//code' 'impl Foo for u32' +// @has - '//div[@id="impl-Foo-for-u32"]//code' 'impl Foo for u32' // @has - '//*[@class="sidebar-links"]/a[@href="#impl-Foo-for-%26%27a%20str"]' "&'a str" -// @has - '//h3[@id="impl-Foo-for-%26%27a%20str"]//code' "impl<'a> Foo for &'a str" +// @has - '//div[@id="impl-Foo-for-%26%27a%20str"]//code' "impl<'a> Foo for &'a str" pub trait Foo {} impl Foo for u32 {} diff --git a/src/test/rustdoc/sized_trait.rs b/src/test/rustdoc/sized_trait.rs index 26d12817afc..6730c71e90f 100644 --- a/src/test/rustdoc/sized_trait.rs +++ b/src/test/rustdoc/sized_trait.rs @@ -1,17 +1,17 @@ #![crate_name = "foo"] // @has foo/struct.Bar.html -// @!has - '//h3[@id="impl-Sized"]' +// @!has - '//div[@id="impl-Sized"]' pub struct Bar { a: u16, } // @has foo/struct.Foo.html -// @!has - '//h3[@id="impl-Sized"]' +// @!has - '//div[@id="impl-Sized"]' pub struct Foo<T: ?Sized>(T); // @has foo/struct.Unsized.html -// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized' +// @has - '//div[@id="impl-Sized"]/code' 'impl !Sized for Unsized' pub struct Unsized { data: [u8], } diff --git a/src/test/rustdoc/spotlight-from-dependency.rs b/src/test/rustdoc/spotlight-from-dependency.rs index ed42c435945..864cb0c400b 100644 --- a/src/test/rustdoc/spotlight-from-dependency.rs +++ b/src/test/rustdoc/spotlight-from-dependency.rs @@ -3,7 +3,7 @@ use std::iter::Iterator; // @has foo/struct.Odd.html -// @has - '//h4[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd' +// @has - '//div[@id="method.new"]//span[@class="notable-traits"]//code/span' 'impl Iterator for Odd' pub struct Odd { current: usize, } diff --git a/src/test/rustdoc/src-links-auto-impls.rs b/src/test/rustdoc/src-links-auto-impls.rs index a1d183df0f1..6f609e080d3 100644 --- a/src/test/rustdoc/src-links-auto-impls.rs +++ b/src/test/rustdoc/src-links-auto-impls.rs @@ -1,12 +1,12 @@ #![crate_name = "foo"] // @has foo/struct.Unsized.html -// @has - '//h3[@id="impl-Sized"]/code' 'impl !Sized for Unsized' -// @!has - '//h3[@id="impl-Sized"]/a[@class="srclink"]' '[src]' -// @has - '//h3[@id="impl-Sync"]/code' 'impl Sync for Unsized' -// @!has - '//h3[@id="impl-Sync"]/a[@class="srclink"]' '[src]' -// @has - '//h3[@id="impl-Any"]/code' 'impl<T> Any for T' -// @has - '//h3[@id="impl-Any"]/a[@class="srclink"]' '[src]' +// @has - '//div[@id="impl-Sized"]/code' 'impl !Sized for Unsized' +// @!has - '//div[@id="impl-Sized"]/a[@class="srclink"]' '[src]' +// @has - '//div[@id="impl-Sync"]/code' 'impl Sync for Unsized' +// @!has - '//div[@id="impl-Sync"]/a[@class="srclink"]' '[src]' +// @has - '//div[@id="impl-Any"]/code' 'impl<T> Any for T' +// @has - '//div[@id="impl-Any"]/a[@class="srclink"]' '[src]' pub struct Unsized { data: [u8], } diff --git a/src/test/rustdoc/synthetic_auto/basic.rs b/src/test/rustdoc/synthetic_auto/basic.rs index 0dd3a3f7a86..943596a0c85 100644 --- a/src/test/rustdoc/synthetic_auto/basic.rs +++ b/src/test/rustdoc/synthetic_auto/basic.rs @@ -1,8 +1,8 @@ // @has basic/struct.Foo.html // @has - '//code' 'impl<T> Send for Foo<T> where T: Send' // @has - '//code' 'impl<T> Sync for Foo<T> where T: Sync' -// @count - '//*[@id="implementations-list"]//*[@class="impl"]' 0 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 5 +// @count - '//*[@id="implementations-list"]//*[@class="impl has-srclink"]' 0 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 5 pub struct Foo<T> { field: T, } diff --git a/src/test/rustdoc/synthetic_auto/complex.rs b/src/test/rustdoc/synthetic_auto/complex.rs index d951a20e2de..0213142266f 100644 --- a/src/test/rustdoc/synthetic_auto/complex.rs +++ b/src/test/rustdoc/synthetic_auto/complex.rs @@ -20,8 +20,8 @@ mod foo { } // @has complex/struct.NotOuter.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'a, T, K: \ -// ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<'a, T, K: ?Sized> Send for Outer<'a, T, K> where K: for<'b> Fn((&'b bool, &'a u8)) \ // -> &'b i8, T: MyTrait<'a>, <T as MyTrait<'a>>::MyItem: Copy, 'a: 'static" pub use foo::{Foo, Inner as NotInner, MyTrait as NotMyTrait, Outer as NotOuter}; diff --git a/src/test/rustdoc/synthetic_auto/lifetimes.rs b/src/test/rustdoc/synthetic_auto/lifetimes.rs index 05c88f10822..c2e9b6f4046 100644 --- a/src/test/rustdoc/synthetic_auto/lifetimes.rs +++ b/src/test/rustdoc/synthetic_auto/lifetimes.rs @@ -9,11 +9,11 @@ where {} // @has lifetimes/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \ -// for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<'c, K> Send for Foo<'c, K> where K: for<'b> Fn(&'b bool) -> &'c u8, 'c: 'static" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \ -// for Foo<'c, K> where K: Sync" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<'c, K> Sync for Foo<'c, K> where K: Sync" pub struct Foo<'c, K: 'c> { inner_field: Inner<'c, K>, } diff --git a/src/test/rustdoc/synthetic_auto/manual.rs b/src/test/rustdoc/synthetic_auto/manual.rs index 88ddd57349a..91fe6c351c5 100644 --- a/src/test/rustdoc/synthetic_auto/manual.rs +++ b/src/test/rustdoc/synthetic_auto/manual.rs @@ -1,12 +1,12 @@ // @has manual/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Sync for \ -// Foo<T> where T: Sync' +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// 'impl<T> Sync for Foo<T> where T: Sync' // -// @has - '//*[@id="trait-implementations-list"]//*[@class="impl"]//code' \ +// @has - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]//code' \ // 'impl<T> Send for Foo<T>' // -// @count - '//*[@id="trait-implementations-list"]//*[@class="impl"]' 1 -// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]' 4 +// @count - '//*[@id="trait-implementations-list"]//*[@class="impl has-srclink"]' 1 +// @count - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]' 4 pub struct Foo<T> { field: T, } diff --git a/src/test/rustdoc/synthetic_auto/negative.rs b/src/test/rustdoc/synthetic_auto/negative.rs index 53801542c95..16b36b56b68 100644 --- a/src/test/rustdoc/synthetic_auto/negative.rs +++ b/src/test/rustdoc/synthetic_auto/negative.rs @@ -3,11 +3,11 @@ pub struct Inner<T: Copy> { } // @has negative/struct.Outer.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> !Send for \ -// Outer<T>" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<T> !Send for Outer<T>" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> \ -// !Sync for Outer<T>" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<T> !Sync for Outer<T>" pub struct Outer<T: Copy> { inner_field: Inner<T>, } diff --git a/src/test/rustdoc/synthetic_auto/nested.rs b/src/test/rustdoc/synthetic_auto/nested.rs index d4d93a87ffc..a6cf5890dca 100644 --- a/src/test/rustdoc/synthetic_auto/nested.rs +++ b/src/test/rustdoc/synthetic_auto/nested.rs @@ -9,10 +9,10 @@ where } // @has nested/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' 'impl<T> Send for \ -// Foo<T> where T: Copy' +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// 'impl<T> Send for Foo<T> where T: Copy' // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' \ +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ // 'impl<T> Sync for Foo<T> where T: Sync' pub struct Foo<T> { inner_field: Inner<T>, diff --git a/src/test/rustdoc/synthetic_auto/no-redundancy.rs b/src/test/rustdoc/synthetic_auto/no-redundancy.rs index 3a23dc2cf95..5c744e3eb3c 100644 --- a/src/test/rustdoc/synthetic_auto/no-redundancy.rs +++ b/src/test/rustdoc/synthetic_auto/no-redundancy.rs @@ -9,8 +9,8 @@ where } // @has no_redundancy/struct.Outer.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \ -// Outer<T> where T: Copy + Send" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<T> Send for Outer<T> where T: Copy + Send" pub struct Outer<T> { inner_field: Inner<T>, } diff --git a/src/test/rustdoc/synthetic_auto/project.rs b/src/test/rustdoc/synthetic_auto/project.rs index 060491e3cf1..baf9924b1ae 100644 --- a/src/test/rustdoc/synthetic_auto/project.rs +++ b/src/test/rustdoc/synthetic_auto/project.rs @@ -23,11 +23,12 @@ where } // @has project/struct.Foo.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Send \ -// for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<'c, K> Send for Foo<'c, K> where K: MyTrait<MyItem = bool>, 'c: 'static" // -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<'c, K> Sync \ -// for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, 'c: 'static," +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<'c, K> Sync for Foo<'c, K> where K: MyTrait, <K as MyTrait>::MyItem: OtherTrait, \ +// 'c: 'static," pub struct Foo<'c, K: 'c> { inner_field: Inner<'c, K>, } diff --git a/src/test/rustdoc/synthetic_auto/self-referential.rs b/src/test/rustdoc/synthetic_auto/self-referential.rs index ecdbdf41b20..e96187e2c96 100644 --- a/src/test/rustdoc/synthetic_auto/self-referential.rs +++ b/src/test/rustdoc/synthetic_auto/self-referential.rs @@ -23,7 +23,7 @@ impl<T> Pattern for Wrapper<T> { // @has self_referential/struct.WriteAndThen.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<P1> Send for \ -// WriteAndThen<P1> where <P1 as Pattern>::Value: Send" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<P1> Send for WriteAndThen<P1> where <P1 as Pattern>::Value: Send" pub struct WriteAndThen<P1>(pub P1::Value,pub <Constrain<P1, Wrapper<P1::Value>> as Pattern>::Value) where P1: Pattern; diff --git a/src/test/rustdoc/synthetic_auto/static-region.rs b/src/test/rustdoc/synthetic_auto/static-region.rs index a10e694c1b2..fc732a08ed4 100644 --- a/src/test/rustdoc/synthetic_auto/static-region.rs +++ b/src/test/rustdoc/synthetic_auto/static-region.rs @@ -3,8 +3,8 @@ pub trait OwnedTrait<'a> { } // @has static_region/struct.Owned.html -// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl"]//code' "impl<T> Send for \ -// Owned<T> where <T as OwnedTrait<'static>>::Reader: Send" +// @has - '//*[@id="synthetic-implementations-list"]//*[@class="impl has-srclink"]//code' \ +// "impl<T> Send for Owned<T> where <T as OwnedTrait<'static>>::Reader: Send" pub struct Owned<T> where T: OwnedTrait<'static> { marker: <T as OwnedTrait<'static>>::Reader, } diff --git a/src/test/rustdoc/item-hide-threshold.rs b/src/test/rustdoc/toggle-item-contents.rs index 8986f72636a..6e3c0b4c681 100644 --- a/src/test/rustdoc/item-hide-threshold.rs +++ b/src/test/rustdoc/toggle-item-contents.rs @@ -1,13 +1,13 @@ #![allow(unused)] -// @has 'item_hide_threshold/struct.PubStruct.html' +// @has 'toggle_item_contents/struct.PubStruct.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 pub struct PubStruct { pub a: usize, pub b: usize, } -// @has 'item_hide_threshold/struct.BigPubStruct.html' +// @has 'toggle_item_contents/struct.BigPubStruct.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields' pub struct BigPubStruct { @@ -26,7 +26,7 @@ pub struct BigPubStruct { pub m: usize, } -// @has 'item_hide_threshold/union.BigUnion.html' +// @has 'toggle_item_contents/union.BigUnion.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields' pub union BigUnion { @@ -45,7 +45,7 @@ pub union BigUnion { pub m: usize, } -// @has 'item_hide_threshold/union.Union.html' +// @has 'toggle_item_contents/union.Union.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 pub union Union { pub a: usize, @@ -53,7 +53,7 @@ pub union Union { pub c: usize, } -// @has 'item_hide_threshold/struct.PrivStruct.html' +// @has 'toggle_item_contents/struct.PrivStruct.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 // @has - '//div[@class="docblock type-decl"]' 'fields omitted' pub struct PrivStruct { @@ -61,7 +61,7 @@ pub struct PrivStruct { b: usize, } -// @has 'item_hide_threshold/enum.Enum.html' +// @has 'toggle_item_contents/enum.Enum.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show fields' pub enum Enum { @@ -72,14 +72,14 @@ pub enum Enum { } } -// @has 'item_hide_threshold/enum.LargeEnum.html' +// @has 'toggle_item_contents/enum.LargeEnum.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show variants' pub enum LargeEnum { A, B, C, D, E, F(u8), G, H, I, J, K, L, M } -// @has 'item_hide_threshold/trait.Trait.html' +// @has 'toggle_item_contents/trait.Trait.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 0 pub trait Trait { type A; @@ -88,7 +88,7 @@ pub trait Trait { fn bar(); } -// @has 'item_hide_threshold/trait.GinormousTrait.html' +// @has 'toggle_item_contents/trait.GinormousTrait.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated items' pub trait GinormousTrait { @@ -111,7 +111,7 @@ pub trait GinormousTrait { fn bar(); } -// @has 'item_hide_threshold/trait.HugeTrait.html' +// @has 'toggle_item_contents/trait.HugeTrait.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show associated constants and methods' pub trait HugeTrait { @@ -133,7 +133,7 @@ pub trait HugeTrait { fn bar(); } -// @has 'item_hide_threshold/trait.BigTrait.html' +// @has 'toggle_item_contents/trait.BigTrait.html' // @count - '//details[@class="rustdoc-toggle type-contents-toggle"]' 1 // @has - '//details[@class="rustdoc-toggle type-contents-toggle"]' 'Show methods' pub trait BigTrait { diff --git a/src/test/rustdoc/toggle-method.rs b/src/test/rustdoc/toggle-method.rs new file mode 100644 index 00000000000..f7f6086a4cb --- /dev/null +++ b/src/test/rustdoc/toggle-method.rs @@ -0,0 +1,18 @@ +#![crate_name = "foo"] + +// Struct methods with documentation should be wrapped in a <details> toggle with an appropriate +// summary. Struct methods with no documentation should not be wrapped. +// +// @has foo/struct.Foo.html +// @has - '//details[@class="rustdoc-toggle method-toggle"]//summary//code' 'is_documented()' +// @has - '//details[@class="rustdoc-toggle method-toggle"]//*[@class="docblock"]' 'is_documented is documented' +// @!has - '//details[@class="rustdoc-toggle method-toggle"]//summary//code' 'not_documented()' +pub struct Foo { +} + +impl Foo { + pub fn not_documented() {} + + /// is_documented is documented + pub fn is_documented() {} +} diff --git a/src/test/rustdoc/toggle-trait-fn.rs b/src/test/rustdoc/toggle-trait-fn.rs new file mode 100644 index 00000000000..0bc5eba75a1 --- /dev/null +++ b/src/test/rustdoc/toggle-trait-fn.rs @@ -0,0 +1,23 @@ +#![crate_name = "foo"] + +// Trait methods with documentation should be wrapped in a <details> toggle with an appropriate +// summary. Trait methods with no documentation should not be wrapped. +// +// @has foo/trait.Foo.html +// @has - '//details[@class="rustdoc-toggle"]//summary//code' 'is_documented()' +// @!has - '//details[@class="rustdoc-toggle"]//summary//code' 'not_documented()' +// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented is documented' +// @has - '//details[@class="rustdoc-toggle"]//summary//code' 'is_documented_optional()' +// @!has - '//details[@class="rustdoc-toggle"]//summary//code' 'not_documented_optional()' +// @has - '//details[@class="rustdoc-toggle"]//*[@class="docblock"]' 'is_documented_optional is documented' +pub trait Foo { + fn not_documented(); + + /// is_documented is documented + fn is_documented(); + + fn not_documented_optional() {} + + /// is_documented_optional is documented + fn is_documented_optional() {} +} diff --git a/src/test/rustdoc/trait-attributes.rs b/src/test/rustdoc/trait-attributes.rs index 2bb24a82193..d0dfb8759e6 100644 --- a/src/test/rustdoc/trait-attributes.rs +++ b/src/test/rustdoc/trait-attributes.rs @@ -2,7 +2,7 @@ pub trait Foo { - // @has foo/trait.Foo.html '//h3[@id="tymethod.foo"]//div[@class="code-attribute"]' '#[must_use]' + // @has foo/trait.Foo.html '//div[@id="tymethod.foo"]//div[@class="code-attribute"]' '#[must_use]' #[must_use] fn foo(); } @@ -11,11 +11,11 @@ pub trait Foo { pub struct Bar; impl Bar { - // @has foo/struct.Bar.html '//h4[@id="method.bar"]//div[@class="code-attribute"]' '#[must_use]' + // @has foo/struct.Bar.html '//div[@id="method.bar"]//div[@class="code-attribute"]' '#[must_use]' #[must_use] pub fn bar() {} - // @has foo/struct.Bar.html '//h4[@id="method.bar2"]//div[@class="code-attribute"]' '#[must_use]' + // @has foo/struct.Bar.html '//div[@id="method.bar2"]//div[@class="code-attribute"]' '#[must_use]' #[must_use] pub fn bar2() {} } diff --git a/src/test/rustdoc/trait-impl-items-links-and-anchors.rs b/src/test/rustdoc/trait-impl-items-links-and-anchors.rs index c6a9313e821..5b7c04c0d44 100644 --- a/src/test/rustdoc/trait-impl-items-links-and-anchors.rs +++ b/src/test/rustdoc/trait-impl-items-links-and-anchors.rs @@ -8,58 +8,58 @@ pub trait MyTrait { impl MyTrait for String { - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-1"]//a[@class="type"]/@href' #associatedtype.Assoc - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1 + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="type"]/@href' #associatedtype.Assoc + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-1"]//a[@class="anchor"]/@href' #associatedtype.Assoc-1 type Assoc = (); - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1 + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="constant"]/@href' #associatedconstant.VALUE + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-1"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-1 const VALUE: u32 = 5; - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function fn trait_function(&self) {} - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1 + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-1"]//a[@class="fnname"]/@href' #method.defaulted_override + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-1"]//a[@class="anchor"]/@href' #method.defaulted_override-1 fn defaulted_override(&self) {} } impl MyTrait for Vec<u8> { - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-2"]//a[@class="type"]/@href' #associatedtype.Assoc - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2 + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="type"]/@href' #associatedtype.Assoc + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-2"]//a[@class="anchor"]/@href' #associatedtype.Assoc-2 type Assoc = (); - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2 + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="constant"]/@href' #associatedconstant.VALUE + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-2"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-2 const VALUE: u32 = 5; - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1 + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' #tymethod.trait_function + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-1"]//a[@class="anchor"]/@href' #method.trait_function-1 fn trait_function(&self) {} - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2 + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-2"]//a[@class="fnname"]/@href' #method.defaulted_override + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-2"]//a[@class="anchor"]/@href' #method.defaulted_override-2 fn defaulted_override(&self) {} } impl MyTrait for MyStruct { - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3 - // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="type"]/@href' trait.MyTrait.html#associatedtype.Assoc - // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-3"]//a[@class="type"]/@href' #associatedtype.Assoc + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedtype.Assoc-3"]//a[@class="anchor"]/@href' #associatedtype.Assoc-3 + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="type"]/@href' trait.MyTrait.html#associatedtype.Assoc + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedtype.Assoc"]//a[@class="anchor"]/@href' #associatedtype.Assoc type Assoc = bool; - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3 - // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE - // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-3"]//a[@class="constant"]/@href' #associatedconstant.VALUE + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="associatedconstant.VALUE-3"]//a[@class="anchor"]/@href' #associatedconstant.VALUE-3 + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedconstant.VALUE"]//a[@class="constant"]/@href' trait.MyTrait.html#associatedconstant.VALUE + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="associatedconstant.VALUE"]//a[@class="anchor"]/@href' #associatedconstant.VALUE const VALUE: u32 = 20; - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2 - // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function - // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-2"]//a[@class="fnname"]/@href' #tymethod.trait_function + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.trait_function-2"]//a[@class="anchor"]/@href' #method.trait_function-2 + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.trait_function"]//a[@class="fnname"]/@href' trait.MyTrait.html#tymethod.trait_function + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.trait_function"]//a[@class="anchor"]/@href' #method.trait_function fn trait_function(&self) {} - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override - // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//h4[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3 - // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override - // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-3"]//a[@class="fnname"]/@href' #method.defaulted_override + // @has trait_impl_items_links_and_anchors/trait.MyTrait.html '//div[@id="method.defaulted_override-3"]//a[@class="anchor"]/@href' #method.defaulted_override-3 + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted_override"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted_override + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted_override"]//a[@class="anchor"]/@href' #method.defaulted_override fn defaulted_override(&self) {} - // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted - // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//h4[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted"]//a[@class="fnname"]/@href' trait.MyTrait.html#method.defaulted + // @has trait_impl_items_links_and_anchors/struct.MyStruct.html '//div[@id="method.defaulted"]//a[@class="anchor"]/@href' #method.defaulted } pub struct MyStruct; diff --git a/src/test/rustdoc/typedef.rs b/src/test/rustdoc/typedef.rs index 7f834d3d5a5..21a7fdda769 100644 --- a/src/test/rustdoc/typedef.rs +++ b/src/test/rustdoc/typedef.rs @@ -9,8 +9,8 @@ impl MyStruct { } // @has typedef/type.MyAlias.html -// @has - '//*[@class="impl"]//code' 'impl MyAlias' -// @has - '//*[@class="impl"]//code' 'impl MyTrait for MyAlias' +// @has - '//*[@class="impl has-srclink"]//code' 'impl MyAlias' +// @has - '//*[@class="impl has-srclink"]//code' 'impl MyTrait for MyAlias' // @has - 'Alias docstring' // @has - '//*[@class="sidebar"]//p[@class="location"]' 'Type Definition MyAlias' // @has - '//*[@class="sidebar"]//a[@href="#implementations"]' 'Methods' diff --git a/src/test/rustdoc/where.rs b/src/test/rustdoc/where.rs index 992cddfe72a..f204a27d7d3 100644 --- a/src/test/rustdoc/where.rs +++ b/src/test/rustdoc/where.rs @@ -11,7 +11,7 @@ pub fn charlie<C>() where C: MyTrait {} pub struct Delta<D>(D); -// @has foo/struct.Delta.html '//*[@class="impl"]//code' \ +// @has foo/struct.Delta.html '//*[@class="impl has-srclink"]//code' \ // "impl<D> Delta<D> where D: MyTrait" impl<D> Delta<D> where D: MyTrait { pub fn delta() {} @@ -19,7 +19,7 @@ impl<D> Delta<D> where D: MyTrait { pub struct Echo<E>(E); -// @has foo/struct.Echo.html '//*[@class="impl"]//code' \ +// @has foo/struct.Echo.html '//*[@class="impl has-srclink"]//code' \ // "impl<E> MyTrait for Echo<E> where E: MyTrait" // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \ // "impl<E> MyTrait for Echo<E> where E: MyTrait" @@ -27,7 +27,7 @@ impl<E> MyTrait for Echo<E> where E: MyTrait {} pub enum Foxtrot<F> { Foxtrot1(F) } -// @has foo/enum.Foxtrot.html '//*[@class="impl"]//code' \ +// @has foo/enum.Foxtrot.html '//*[@class="impl has-srclink"]//code' \ // "impl<F> MyTrait for Foxtrot<F> where F: MyTrait" // @has foo/trait.MyTrait.html '//*[@id="implementors-list"]//code' \ // "impl<F> MyTrait for Foxtrot<F> where F: MyTrait" diff --git a/src/test/ui/async-await/async-await.rs b/src/test/ui/async-await/async-await.rs index 0207752afe0..3d22025bf28 100644 --- a/src/test/ui/async-await/async-await.rs +++ b/src/test/ui/async-await/async-await.rs @@ -1,7 +1,8 @@ // run-pass -// revisions: default nomiropt +// revisions: default nomiropt thirunsafeck //[nomiropt]compile-flags: -Z mir-opt-level=0 +//[thirunsafeck]compile-flags: -Zthir-unsafeck #![allow(unused)] diff --git a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs index 2ed343b4a07..fc37822cb7b 100644 --- a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs +++ b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.rs @@ -16,6 +16,6 @@ async fn g() { } fn main() { - S::f(); //~ ERROR call to unsafe function is unsafe - f(); //~ ERROR call to unsafe function is unsafe + S::f(); //[mir]~ ERROR call to unsafe function is unsafe + f(); //[mir]~ ERROR call to unsafe function is unsafe } diff --git a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr index d22413beecb..21ba45d7f1e 100644 --- a/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr +++ b/src/test/ui/async-await/async-unsafe-fn-call-in-safe.thir.stderr @@ -14,22 +14,6 @@ LL | f(); | = note: consult the function's documentation for information on how to avoid undefined behavior -error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/async-unsafe-fn-call-in-safe.rs:19:5 - | -LL | S::f(); - | ^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - -error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/async-unsafe-fn-call-in-safe.rs:20:5 - | -LL | f(); - | ^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs index 4a8e841b33d..9fe3313ee6c 100644 --- a/src/test/ui/async-await/issue-61076.rs +++ b/src/test/ui/async-await/issue-61076.rs @@ -42,7 +42,7 @@ async fn bar() -> Result<(), ()> { foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` //~^ NOTE the `?` operator cannot be applied to type `impl Future` //~| HELP the trait `Try` is not implemented for `impl Future` - //~| NOTE required by `into_result` + //~| NOTE required by `branch` //~| HELP consider `await`ing on the `Future` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` @@ -65,7 +65,7 @@ async fn baz() -> Result<(), ()> { t?; //~ ERROR the `?` operator can only be applied to values that implement `Try` //~^ NOTE the `?` operator cannot be applied to type `T` //~| HELP the trait `Try` is not implemented for `T` - //~| NOTE required by `into_result` + //~| NOTE required by `branch` //~| HELP consider `await`ing on the `Future` //~| NOTE in this expansion of desugaring of operator `?` //~| NOTE in this expansion of desugaring of operator `?` diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr index fd00522fac7..ad661fb2833 100644 --- a/src/test/ui/async-await/issue-61076.stderr +++ b/src/test/ui/async-await/issue-61076.stderr @@ -5,7 +5,7 @@ LL | foo()?; | ^^^^^^ the `?` operator cannot be applied to type `impl Future` | = help: the trait `Try` is not implemented for `impl Future` - = note: required by `into_result` + = note: required by `branch` help: consider `await`ing on the `Future` | LL | foo().await?; @@ -18,7 +18,7 @@ LL | t?; | ^^ the `?` operator cannot be applied to type `T` | = help: the trait `Try` is not implemented for `T` - = note: required by `into_result` + = note: required by `branch` help: consider `await`ing on the `Future` | LL | t.await?; diff --git a/src/test/ui/async-await/issue-73741-type-err.rs b/src/test/ui/async-await/issue-73741-type-err.rs new file mode 100644 index 00000000000..c5b9e34edf7 --- /dev/null +++ b/src/test/ui/async-await/issue-73741-type-err.rs @@ -0,0 +1,14 @@ +// edition:2018 +// +// Regression test for issue #73741 +// Ensures that we don't emit spurious errors when +// a type error ocurrs in an `async fn` + +async fn weird() { + 1 = 2; //~ ERROR invalid left-hand side + + let mut loop_count = 0; + async {}.await +} + +fn main() {} diff --git a/src/test/ui/async-await/issue-73741-type-err.stderr b/src/test/ui/async-await/issue-73741-type-err.stderr new file mode 100644 index 00000000000..0b5343a98cf --- /dev/null +++ b/src/test/ui/async-await/issue-73741-type-err.stderr @@ -0,0 +1,11 @@ +error[E0070]: invalid left-hand side of assignment + --> $DIR/issue-73741-type-err.rs:8:7 + | +LL | 1 = 2; + | - ^ + | | + | cannot assign to this expression + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0070`. diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs index b901b61aa18..f1002947fb9 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-fg.rs @@ -1,10 +1,9 @@ // edition:2018 // run-pass -// Test that a feature gate is needed to use `impl Trait` as the -// return type of an async. - -#![feature(member_constraints)] +// Test member constraints that appear in the `impl Trait` +// return type of an async function. +// (This used to require a feature gate.) trait Trait<'a, 'b> { } impl<T> Trait<'_, '_> for T { } diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs deleted file mode 100644 index 05960c0c7f6..00000000000 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.rs +++ /dev/null @@ -1,20 +0,0 @@ -// edition:2018 - -// Test that a feature gate is needed to use `impl Trait` as the -// return type of an async. - -trait Trait<'a, 'b> { } -impl<T> Trait<'_, '_> for T { } - -async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { - //~^ ERROR ambiguous lifetime bound - //~| ERROR ambiguous lifetime bound - //~| ERROR ambiguous lifetime bound - //~| ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds - //~| ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds - (a, b) -} - -fn main() { - let _ = async_ret_impl_trait(&22, &44); -} diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr deleted file mode 100644 index f65bbeaa31a..00000000000 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-no-fg.stderr +++ /dev/null @@ -1,43 +0,0 @@ -error: ambiguous lifetime bound in `impl Trait` - --> $DIR/ret-impl-trait-no-fg.rs:9:64 - | -LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { - | ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other - | - = help: add #![feature(member_constraints)] to the crate attributes to enable - -error: ambiguous lifetime bound in `impl Trait` - --> $DIR/ret-impl-trait-no-fg.rs:9:64 - | -LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { - | ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other - | - = help: add #![feature(member_constraints)] to the crate attributes to enable - -error: ambiguous lifetime bound in `impl Trait` - --> $DIR/ret-impl-trait-no-fg.rs:9:64 - | -LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { - | ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another - | - = help: add #![feature(member_constraints)] to the crate attributes to enable - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ret-impl-trait-no-fg.rs:9:1 - | -LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: hidden type `(&u8, &u8)` captures lifetime '_#5r - -error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ret-impl-trait-no-fg.rs:9:1 - | -LL | async fn async_ret_impl_trait<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: hidden type `(&u8, &u8)` captures lifetime '_#6r - -error: aborting due to 5 previous errors - -For more information about this error, try `rustc --explain E0700`. diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr index 53b0dd691b8..eed90772d29 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.nll.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/ret-impl-trait-one.rs:12:80 + --> $DIR/ret-impl-trait-one.rs:10:80 | LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> { | ________________________________--__--__________________________________________^ diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs index babc90a5e96..7e084217c26 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.rs @@ -3,8 +3,6 @@ // Test that a feature gate is needed to use `impl Trait` as the // return type of an async. -#![feature(member_constraints)] - trait Trait<'a> { } impl<T> Trait<'_> for T { } diff --git a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr index 5041b39a9e9..8e28605721c 100644 --- a/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr +++ b/src/test/ui/async-await/multiple-lifetimes/ret-impl-trait-one.stderr @@ -1,5 +1,5 @@ error[E0623]: lifetime mismatch - --> $DIR/ret-impl-trait-one.rs:12:65 + --> $DIR/ret-impl-trait-one.rs:10:65 | LL | async fn async_ret_impl_trait1<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a> { | ------ ^^^^^^^^^^^^^^ diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr index 8e7823f3571..a3f122a4663 100644 --- a/src/test/ui/async-await/try-on-option-in-async.stderr +++ b/src/test/ui/async-await/try-on-option-in-async.stderr @@ -1,47 +1,47 @@ -error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-on-option-in-async.rs:8:9 +error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-on-option-in-async.rs:8:10 | LL | async { | ___________- LL | | let x: Option<u32> = None; LL | | x?; - | | ^^ cannot use the `?` operator in an async block that returns `{integer}` + | | ^ cannot use the `?` operator in an async block that returns `{integer}` LL | | 22 LL | | } | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `{integer}` - = note: required by `from_error` + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}` + = note: required by `from_residual` -error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-on-option-in-async.rs:17:9 +error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-on-option-in-async.rs:17:10 | LL | let async_closure = async || { | __________________________________- LL | | let x: Option<u32> = None; LL | | x?; - | | ^^ cannot use the `?` operator in an async closure that returns `u32` + | | ^ cannot use the `?` operator in an async closure that returns `u32` LL | | 22_u32 LL | | }; | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `u32` - = note: required by `from_error` + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32` + = note: required by `from_residual` -error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-on-option-in-async.rs:26:5 +error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-on-option-in-async.rs:26:6 | LL | async fn an_async_function() -> u32 { | _____________________________________- LL | | let x: Option<u32> = None; LL | | x?; - | | ^^ cannot use the `?` operator in an async function that returns `u32` + | | ^ cannot use the `?` operator in an async function that returns `u32` LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `u32` - = note: required by `from_error` + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32` + = note: required by `from_residual` error: aborting due to 3 previous errors diff --git a/src/test/ui/attributes/key-value-expansion-on-mac.rs b/src/test/ui/attributes/key-value-expansion-on-mac.rs index 1247ff2b230..95bc1c04961 100644 --- a/src/test/ui/attributes/key-value-expansion-on-mac.rs +++ b/src/test/ui/attributes/key-value-expansion-on-mac.rs @@ -1,4 +1,3 @@ -#![feature(extended_key_value_attributes)] #![feature(rustc_attrs)] #[rustc_dummy = stringify!(a)] // OK diff --git a/src/test/ui/attributes/key-value-expansion-on-mac.stderr b/src/test/ui/attributes/key-value-expansion-on-mac.stderr index b74f3518a7e..fa9ea543765 100644 --- a/src/test/ui/attributes/key-value-expansion-on-mac.stderr +++ b/src/test/ui/attributes/key-value-expansion-on-mac.stderr @@ -1,5 +1,5 @@ error: unexpected token: `stringify!(b)` - --> $DIR/key-value-expansion-on-mac.rs:12:17 + --> $DIR/key-value-expansion-on-mac.rs:11:17 | LL | #[rustc_dummy = stringify!(b)] | ^^^^^^^^^^^^^ diff --git a/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr b/src/test/ui/cast/cast-ptr-to-int-const.mir.stderr index 8282bc3db05..dcc9a243f0f 100644 --- a/src/test/ui/cast/cast-ptr-to-int-const.with_feature.stderr +++ b/src/test/ui/cast/cast-ptr-to-int-const.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block - --> $DIR/cast-ptr-to-int-const.rs:16:9 + --> $DIR/cast-ptr-to-int-const.rs:10:9 | LL | &Y as *const u32 as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int @@ -7,7 +7,7 @@ LL | &Y as *const u32 as usize = note: casting pointers to integers in constants error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block - --> $DIR/cast-ptr-to-int-const.rs:23:5 + --> $DIR/cast-ptr-to-int-const.rs:17:5 | LL | &0 as *const i32 as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int diff --git a/src/test/ui/cast/cast-ptr-to-int-const.rs b/src/test/ui/cast/cast-ptr-to-int-const.rs index aed099a53ea..01ea627679d 100644 --- a/src/test/ui/cast/cast-ptr-to-int-const.rs +++ b/src/test/ui/cast/cast-ptr-to-int-const.rs @@ -1,25 +1,19 @@ -// gate-test-const_raw_ptr_to_usize_cast -// revisions: with_feature without_feature +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck -#![cfg_attr(with_feature, feature(const_raw_ptr_to_usize_cast))] +#![feature(const_raw_ptr_to_usize_cast)] fn main() { - const X: usize = unsafe { - main as usize //[without_feature]~ ERROR casting pointers to integers in constants is unstable - }; const Y: u32 = 0; - const Z: usize = unsafe { - &Y as *const u32 as usize //[without_feature]~ ERROR is unstable - }; // Cast in `const` without `unsafe` block const SAFE: usize = { - &Y as *const u32 as usize //[without_feature]~ ERROR is unstable - //[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe + &Y as *const u32 as usize + //~^ ERROR cast of pointer to int is unsafe and requires unsafe }; } // Cast in `const fn` without `unsafe` block const fn test() -> usize { - &0 as *const i32 as usize //[without_feature]~ ERROR is unstable - //[with_feature]~^ ERROR cast of pointer to int is unsafe and requires unsafe + &0 as *const i32 as usize + //~^ ERROR cast of pointer to int is unsafe and requires unsafe } diff --git a/src/test/ui/cast/cast-ptr-to-int-const.thir.stderr b/src/test/ui/cast/cast-ptr-to-int-const.thir.stderr new file mode 100644 index 00000000000..dcc9a243f0f --- /dev/null +++ b/src/test/ui/cast/cast-ptr-to-int-const.thir.stderr @@ -0,0 +1,19 @@ +error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block + --> $DIR/cast-ptr-to-int-const.rs:10:9 + | +LL | &Y as *const u32 as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int + | + = note: casting pointers to integers in constants + +error[E0133]: cast of pointer to int is unsafe and requires unsafe function or block + --> $DIR/cast-ptr-to-int-const.rs:17:5 + | +LL | &0 as *const i32 as usize + | ^^^^^^^^^^^^^^^^^^^^^^^^^ cast of pointer to int + | + = note: casting pointers to integers in constants + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs new file mode 100644 index 00000000000..03e99eb7527 --- /dev/null +++ b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.rs @@ -0,0 +1,13 @@ +fn main() { + const X: usize = unsafe { + main as usize //~ ERROR casting pointers to integers in constants is unstable + }; + const Y: u32 = 0; + const Z: usize = unsafe { + &Y as *const u32 as usize //~ ERROR is unstable + }; +} + +const fn test() -> usize { + &0 as *const i32 as usize //~ ERROR is unstable +} diff --git a/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.stderr index c87fa1a14a4..4a0b424e181 100644 --- a/src/test/ui/cast/cast-ptr-to-int-const.without_feature.stderr +++ b/src/test/ui/cast/feature-gate-const_raw_ptr_to_usize_cast.stderr @@ -1,5 +1,5 @@ error[E0658]: casting pointers to integers in constants is unstable - --> $DIR/cast-ptr-to-int-const.rs:8:9 + --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:3:9 | LL | main as usize | ^^^^^^^^^^^^^ @@ -8,16 +8,7 @@ LL | main as usize = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constants is unstable - --> $DIR/cast-ptr-to-int-const.rs:12:9 - | -LL | &Y as *const u32 as usize - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information - = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable - -error[E0658]: casting pointers to integers in constants is unstable - --> $DIR/cast-ptr-to-int-const.rs:16:9 + --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:7:9 | LL | &Y as *const u32 as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -26,7 +17,7 @@ LL | &Y as *const u32 as usize = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable error[E0658]: casting pointers to integers in constant functions is unstable - --> $DIR/cast-ptr-to-int-const.rs:23:5 + --> $DIR/feature-gate-const_raw_ptr_to_usize_cast.rs:12:5 | LL | &0 as *const i32 as usize | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -34,6 +25,6 @@ LL | &0 as *const i32 as usize = note: see issue #51910 <https://github.com/rust-lang/rust/issues/51910> for more information = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/cast/issue-84213.stderr b/src/test/ui/cast/issue-84213.stderr index 1b71d4db511..90cfa263c52 100644 --- a/src/test/ui/cast/issue-84213.stderr +++ b/src/test/ui/cast/issue-84213.stderr @@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `Something` as `*const Something` LL | let _pointer_to_something = something as *const Something; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast | -help: borrow the value for the cast to be valid +help: consider borrowing the value | LL | let _pointer_to_something = &something as *const Something; | ^ @@ -15,7 +15,7 @@ error[E0605]: non-primitive cast: `Something` as `*mut Something` LL | let _mut_pointer_to_something = something as *mut Something; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast | -help: borrow the value for the cast to be valid +help: consider borrowing the value | LL | let _mut_pointer_to_something = &mut something as *mut Something; | ^^^^ diff --git a/src/test/ui/command/command-pre-exec.rs b/src/test/ui/command/command-pre-exec.rs index 819ed0b2dde..61914e22930 100644 --- a/src/test/ui/command/command-pre-exec.rs +++ b/src/test/ui/command/command-pre-exec.rs @@ -1,4 +1,6 @@ // run-pass +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck #![allow(stable_features)] // ignore-windows - this is a unix-specific test diff --git a/src/test/ui/confuse-field-and-method/issue-18343.stderr b/src/test/ui/confuse-field-and-method/issue-18343.stderr index d6b399acb73..fe6b12968c1 100644 --- a/src/test/ui/confuse-field-and-method/issue-18343.stderr +++ b/src/test/ui/confuse-field-and-method/issue-18343.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-18343.rs:6:28: 6:33]>` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-18343.rs:7:7 | LL | struct Obj<F> where F: FnMut() -> u32 { diff --git a/src/test/ui/confuse-field-and-method/issue-2392.stderr b/src/test/ui/confuse-field-and-method/issue-2392.stderr index 051940bbe96..0480958e99c 100644 --- a/src/test/ui/confuse-field-and-method/issue-2392.stderr +++ b/src/test/ui/confuse-field-and-method/issue-2392.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:36:15 | LL | struct Obj<F> where F: FnOnce() -> u32 { @@ -12,7 +12,7 @@ help: to call the function stored in `closure`, surround the field access with p LL | (o_closure.closure)(); | ^ ^ -error[E0599]: no method named `not_closure` found for struct `Obj<[closure@$DIR/issue-2392.rs:35:36: 35:41]>` in the current scope +error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:38:15 | LL | struct Obj<F> where F: FnOnce() -> u32 { @@ -23,7 +23,7 @@ LL | o_closure.not_closure(); | | | field, not a method -error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:42:12 | LL | struct Obj<F> where F: FnOnce() -> u32 { @@ -65,7 +65,7 @@ help: to call the function stored in `boxed_closure`, surround the field access LL | (boxed_closure.boxed_closure)(); | ^ ^ -error[E0599]: no method named `closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:53:12 | LL | struct Obj<F> where F: FnOnce() -> u32 { @@ -79,7 +79,7 @@ help: to call the function stored in `closure`, surround the field access with p LL | (w.wrap.closure)(); | ^ ^ -error[E0599]: no method named `not_closure` found for struct `Obj<fn() -> u32 {func}>` in the current scope +error[E0599]: no method named `not_closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:55:12 | LL | struct Obj<F> where F: FnOnce() -> u32 { @@ -90,7 +90,7 @@ LL | w.wrap.not_closure(); | | | field, not a method -error[E0599]: no method named `closure` found for struct `Obj<Box<(dyn FnOnce() -> u32 + 'static)>>` in the current scope +error[E0599]: no method named `closure` found for struct `Obj` in the current scope --> $DIR/issue-2392.rs:58:24 | LL | struct Obj<F> where F: FnOnce() -> u32 { diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs index 05049d9c2a6..26c4295cd9b 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.rs @@ -9,6 +9,7 @@ struct Foo<T>(PhantomData<T>); fn test<T>() -> [u8; size_of::<T>()] { [0; size_of::<Foo<T>>()] //~^ ERROR unconstrained generic constant + //~| ERROR mismatched types } fn main() { diff --git a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr index 7c11a47b2f0..2aeb9b961ff 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/different-fn.stderr @@ -1,3 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/different-fn.rs:10:5 + | +LL | [0; size_of::<Foo<T>>()] + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `size_of::<T>()`, found `size_of::<Foo<T>>()` + | + = note: expected type `size_of::<T>()` + found type `size_of::<Foo<T>>()` + error: unconstrained generic constant --> $DIR/different-fn.rs:10:9 | @@ -6,5 +15,6 @@ LL | [0; size_of::<Foo<T>>()] | = help: try adding a `where` bound using this expression: `where [(); size_of::<Foo<T>>()]:` -error: aborting due to previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs b/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs new file mode 100644 index 00000000000..0f36ce383a8 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/evaluated-to-ambig.rs @@ -0,0 +1,22 @@ +// check-pass + +// We previously always returned ambiguity when equating generic consts, even if they +// only contain generic parameters. This is incorrect as trying to unify `N > 1` with `M > 1` +// should fail. +#![allow(incomplete_features)] +#![feature(const_generics, const_evaluatable_checked)] + +enum Assert<const COND: bool> {} +trait IsTrue {} +impl IsTrue for Assert<true> {} + +struct Foo<const N: usize, const M: usize>; +trait Bar<const N: usize, const M: usize> {} +impl<const N: usize, const M: usize> Bar<N, M> for Foo<N, M> +where + Assert<{ N > 1 }>: IsTrue, + Assert<{ M > 1 }>: IsTrue, +{ +} + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs index 3da4688702c..8167d785d7a 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs @@ -2,7 +2,7 @@ #![allow(incomplete_features)] fn test<const N: usize>() -> [u8; N - 1] { - //~^ ERROR evaluation of constant + //~^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed todo!() } diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr index 25af18eb162..31ccf979694 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr @@ -1,4 +1,4 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed --> $DIR/from-sig-fail.rs:4:35 | LL | fn test<const N: usize>() -> [u8; N - 1] { diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr index acf0a52ce5b..1f2313a6028 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr @@ -1,10 +1,10 @@ -error[E0080]: evaluation of constant value failed - --> $DIR/simple_fail.rs:9:48 +error[E0080]: evaluation of `test::<0_usize>::{constant#0}` failed + --> $DIR/simple_fail.rs:10:48 | LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized { | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation of `Arr::<0_usize>::{constant#0}` failed --> $DIR/simple_fail.rs:6:33 | LL | type Arr<const N: usize> = [u8; N - 1]; diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr index fe5463f8acc..1aa66f9a8ba 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr @@ -8,7 +8,7 @@ LL | type Arr<const N: usize> = [u8; N - 1]; = help: use `#![feature(const_generics)]` and `#![feature(const_evaluatable_checked)]` to allow generic const expressions error: generic parameters may not be used in const operations - --> $DIR/simple_fail.rs:9:48 + --> $DIR/simple_fail.rs:10:48 | LL | fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized { | ^ cannot perform const operation using `N` diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs index c9535d04244..f08d2495b4d 100644 --- a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs @@ -3,12 +3,13 @@ #![cfg_attr(full, feature(const_evaluatable_checked))] #![allow(incomplete_features)] -type Arr<const N: usize> = [u8; N - 1]; //[full]~ ERROR evaluation of constant +type Arr<const N: usize> = [u8; N - 1]; //[min]~^ ERROR generic parameters may not be used in const operations +//[full]~^^ ERROR evaluation of `Arr::<0_usize>::{constant#0}` failed fn test<const N: usize>() -> Arr<N> where [u8; N - 1]: Sized { //[min]~^ ERROR generic parameters may not be used in const operations -//[full]~^^ ERROR evaluation of constant +//[full]~^^ ERROR evaluation of `test::<0_usize>::{constant#0}` failed todo!() } diff --git a/src/test/ui/const-generics/defaults/const-param-as-default-value.rs b/src/test/ui/const-generics/defaults/const-param-as-default-value.rs index 59ac261f44f..9779835d315 100644 --- a/src/test/ui/const-generics/defaults/const-param-as-default-value.rs +++ b/src/test/ui/const-generics/defaults/const-param-as-default-value.rs @@ -1,6 +1,5 @@ // run-pass #![feature(const_generics_defaults)] -#![allow(incomplete_features)] struct Foo<const N: usize, const M: usize = N>([u8; N], [u8; M]); fn foo<const N: usize>() -> Foo<N> { diff --git a/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs b/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs index 3f534ca0308..dbcab77dcd2 100644 --- a/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs +++ b/src/test/ui/const-generics/defaults/const-param-in-ty-defaults.rs @@ -1,6 +1,5 @@ // run-pass #![feature(const_generics_defaults)] -#![allow(incomplete_features)] struct Foo<const N: usize, T = [u8; N]>(T); impl<const N: usize> Foo<N> { diff --git a/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs b/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs index 4bb56c6a1c0..d4271adefd1 100644 --- a/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs +++ b/src/test/ui/const-generics/defaults/default-param-wf-concrete.rs @@ -1,5 +1,4 @@ #![feature(const_generics_defaults)] -#![allow(incomplete_features)] struct Foo<const N: u8 = { 255 + 1 }>; //~^ ERROR evaluation of constant value failed fn main() {} diff --git a/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr b/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr index 8464ea98bf6..6fca9d31c0a 100644 --- a/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr +++ b/src/test/ui/const-generics/defaults/default-param-wf-concrete.stderr @@ -1,5 +1,5 @@ error[E0080]: evaluation of constant value failed - --> $DIR/default-param-wf-concrete.rs:3:28 + --> $DIR/default-param-wf-concrete.rs:2:28 | LL | struct Foo<const N: u8 = { 255 + 1 }>; | ^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow diff --git a/src/test/ui/const-generics/defaults/forward-declared.rs b/src/test/ui/const-generics/defaults/forward-declared.rs new file mode 100644 index 00000000000..09fc105320e --- /dev/null +++ b/src/test/ui/const-generics/defaults/forward-declared.rs @@ -0,0 +1,15 @@ +#![feature(const_generics_defaults)] + +struct Foo<const N: usize = M, const M: usize = 10>; +//~^ ERROR generic parameters with a default cannot use forward declared identifiers + +enum Bar<const N: usize = M, const M: usize = 10> {} +//~^ ERROR generic parameters with a default cannot use forward declared identifiers + +struct Foo2<const N: usize = N>; +//~^ ERROR generic parameters with a default cannot use forward declared identifiers + +enum Bar2<const N: usize = N> {} +//~^ ERROR generic parameters with a default cannot use forward declared identifiers + +fn main() {} diff --git a/src/test/ui/const-generics/defaults/forward-declared.stderr b/src/test/ui/const-generics/defaults/forward-declared.stderr new file mode 100644 index 00000000000..a6c4a7ae4ef --- /dev/null +++ b/src/test/ui/const-generics/defaults/forward-declared.stderr @@ -0,0 +1,27 @@ +error[E0128]: generic parameters with a default cannot use forward declared identifiers + --> $DIR/forward-declared.rs:3:29 + | +LL | struct Foo<const N: usize = M, const M: usize = 10>; + | ^ defaulted generic parameters cannot be forward declared + +error[E0128]: generic parameters with a default cannot use forward declared identifiers + --> $DIR/forward-declared.rs:6:27 + | +LL | enum Bar<const N: usize = M, const M: usize = 10> {} + | ^ defaulted generic parameters cannot be forward declared + +error[E0128]: generic parameters with a default cannot use forward declared identifiers + --> $DIR/forward-declared.rs:9:30 + | +LL | struct Foo2<const N: usize = N>; + | ^ defaulted generic parameters cannot be forward declared + +error[E0128]: generic parameters with a default cannot use forward declared identifiers + --> $DIR/forward-declared.rs:12:28 + | +LL | enum Bar2<const N: usize = N> {} + | ^ defaulted generic parameters cannot be forward declared + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0128`. diff --git a/src/test/ui/const-generics/defaults/pretty-printing-ast.rs b/src/test/ui/const-generics/defaults/pretty-printing-ast.rs index 7a57950dfc9..0487668cd2a 100644 --- a/src/test/ui/const-generics/defaults/pretty-printing-ast.rs +++ b/src/test/ui/const-generics/defaults/pretty-printing-ast.rs @@ -4,7 +4,6 @@ #![crate_type = "lib"] #![feature(const_generics_defaults)] -#![allow(incomplete_features)] trait Foo<const KIND: bool = true> {} diff --git a/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout b/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout index f549993c413..1bceb8cbb94 100644 --- a/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout +++ b/src/test/ui/const-generics/defaults/pretty-printing-ast.stdout @@ -6,7 +6,6 @@ #![crate_type = "lib"] #![feature(const_generics_defaults)] -#![allow(incomplete_features)] #[prelude_import] use ::std::prelude::rust_2015::*; #[macro_use] diff --git a/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs b/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs index c64c2974c8f..ca29ee94206 100644 --- a/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs +++ b/src/test/ui/const-generics/defaults/repr-c-issue-82792.rs @@ -3,7 +3,6 @@ // run-pass #![feature(const_generics_defaults)] -#![allow(incomplete_features)] #[repr(C)] pub struct Loaf<T: Sized, const N: usize = 1> { diff --git a/src/test/ui/const-generics/issues/issue-62504.full.stderr b/src/test/ui/const-generics/issues/issue-62504.full.stderr index f09af76325e..efbcdc3d2b7 100644 --- a/src/test/ui/const-generics/issues/issue-62504.full.stderr +++ b/src/test/ui/const-generics/issues/issue-62504.full.stderr @@ -1,3 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/issue-62504.rs:18:21 + | +LL | ArrayHolder([0; Self::SIZE]) + | ^^^^^^^^^^^^^^^ expected `X`, found `Self::SIZE` + | + = note: expected type `X` + found type `Self::SIZE` + error: constant expression depends on a generic parameter --> $DIR/issue-62504.rs:18:25 | @@ -6,5 +15,6 @@ LL | ArrayHolder([0; Self::SIZE]) | = note: this may fail depending on what value the parameter takes -error: aborting due to previous error +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs index 0b95754cab4..1b70cd1c376 100644 --- a/src/test/ui/const-generics/issues/issue-62504.rs +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -17,7 +17,7 @@ impl<const X: usize> ArrayHolder<X> { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) //~^ ERROR constant expression depends on a generic parameter - //[min]~| ERROR mismatched types + //~| ERROR mismatched types } } diff --git a/src/test/ui/const-generics/min_const_generics/default_function_param.rs b/src/test/ui/const-generics/min_const_generics/default_function_param.rs index ebdb5a65bc3..b47dd2f618c 100644 --- a/src/test/ui/const-generics/min_const_generics/default_function_param.rs +++ b/src/test/ui/const-generics/min_const_generics/default_function_param.rs @@ -1,6 +1,5 @@ #![crate_type = "lib"] #![feature(const_generics_defaults)] -#![allow(incomplete_features)] fn foo<const SIZE: usize = 5usize>() {} //~^ ERROR defaults for const parameters are diff --git a/src/test/ui/const-generics/min_const_generics/default_function_param.stderr b/src/test/ui/const-generics/min_const_generics/default_function_param.stderr index 243ac0db5f5..11df8621faa 100644 --- a/src/test/ui/const-generics/min_const_generics/default_function_param.stderr +++ b/src/test/ui/const-generics/min_const_generics/default_function_param.stderr @@ -1,5 +1,5 @@ error: defaults for const parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions - --> $DIR/default_function_param.rs:5:14 + --> $DIR/default_function_param.rs:4:14 | LL | fn foo<const SIZE: usize = 5usize>() {} | ^^^^ diff --git a/src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs b/src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs new file mode 100644 index 00000000000..bdeaa0cd360 --- /dev/null +++ b/src/test/ui/consts/const-eval/auxiliary/post_monomorphization_error.rs @@ -0,0 +1,20 @@ +// Auxiliary crate used for testing post-monomorphization errors cross-crate. +// It duplicates the setup used in `stdarch` to validate its intrinsics' const arguments. + +struct ValidateConstImm<const IMM: i32, const MIN: i32, const MAX: i32>; +impl<const IMM: i32, const MIN: i32, const MAX: i32> ValidateConstImm<IMM, MIN, MAX> { + pub(crate) const VALID: () = { + let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize); + }; +} + +macro_rules! static_assert_imm1 { + ($imm:ident) => { + let _ = $crate::ValidateConstImm::<$imm, 0, { (1 << 1) - 1 }>::VALID; + }; +} + +// This function triggers an error whenever the const argument does not fit in 1-bit. +pub fn stdarch_intrinsic<const IMM1: i32>() { + static_assert_imm1!(IMM1); +} diff --git a/src/test/ui/consts/const-eval/const_panic.rs b/src/test/ui/consts/const-eval/const_panic.rs index 8ae8376ae4a..b33b1475a22 100644 --- a/src/test/ui/consts/const-eval/const_panic.rs +++ b/src/test/ui/consts/const-eval/const_panic.rs @@ -6,40 +6,30 @@ const MSG: &str = "hello"; const Z: () = std::panic!("cheese"); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out const Z2: () = std::panic!(); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out const Y: () = std::unreachable!(); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out const X: () = std::unimplemented!(); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out // const W: () = std::panic!(MSG); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out const Z_CORE: () = core::panic!("cheese"); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out const Z2_CORE: () = core::panic!(); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out const Y_CORE: () = core::unreachable!(); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out const X_CORE: () = core::unimplemented!(); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out const W_CORE: () = core::panic!(MSG); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out diff --git a/src/test/ui/consts/const-eval/const_panic.stderr b/src/test/ui/consts/const-eval/const_panic.stderr index 5637de8b313..3c890f78af7 100644 --- a/src/test/ui/consts/const-eval/const_panic.stderr +++ b/src/test/ui/consts/const-eval/const_panic.stderr @@ -1,4 +1,4 @@ -error: any use of this value will cause an error +error[E0080]: any use of this value will cause an error --> $DIR/const_panic.rs:7:15 | LL | const Z: () = std::panic!("cheese"); @@ -6,118 +6,98 @@ LL | const Z: () = std::panic!("cheese"); | | | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:7:15 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: any use of this value will cause an error - --> $DIR/const_panic.rs:11:16 +error[E0080]: any use of this value will cause an error + --> $DIR/const_panic.rs:10:16 | LL | const Z2: () = std::panic!(); | ---------------^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:11:16 + | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:10:16 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: any use of this value will cause an error - --> $DIR/const_panic.rs:15:15 +error[E0080]: any use of this value will cause an error + --> $DIR/const_panic.rs:13:15 | LL | const Y: () = std::unreachable!(); | --------------^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:15:15 + | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:13:15 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: any use of this value will cause an error - --> $DIR/const_panic.rs:19:15 +error[E0080]: any use of this value will cause an error + --> $DIR/const_panic.rs:16:15 | LL | const X: () = std::unimplemented!(); | --------------^^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:19:15 + | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:16:15 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: any use of this value will cause an error - --> $DIR/const_panic.rs:23:15 +error[E0080]: any use of this value will cause an error + --> $DIR/const_panic.rs:19:15 | LL | const W: () = std::panic!(MSG); | --------------^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'hello', $DIR/const_panic.rs:23:15 + | the evaluated program panicked at 'hello', $DIR/const_panic.rs:19:15 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: any use of this value will cause an error - --> $DIR/const_panic.rs:27:20 +error[E0080]: any use of this value will cause an error + --> $DIR/const_panic.rs:22:20 | LL | const Z_CORE: () = core::panic!("cheese"); | -------------------^^^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:27:20 + | the evaluated program panicked at 'cheese', $DIR/const_panic.rs:22:20 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: any use of this value will cause an error - --> $DIR/const_panic.rs:31:21 +error[E0080]: any use of this value will cause an error + --> $DIR/const_panic.rs:25:21 | LL | const Z2_CORE: () = core::panic!(); | --------------------^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:31:21 + | the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:25:21 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: any use of this value will cause an error - --> $DIR/const_panic.rs:35:20 +error[E0080]: any use of this value will cause an error + --> $DIR/const_panic.rs:28:20 | LL | const Y_CORE: () = core::unreachable!(); | -------------------^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:35:20 + | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:28:20 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: any use of this value will cause an error - --> $DIR/const_panic.rs:39:20 +error[E0080]: any use of this value will cause an error + --> $DIR/const_panic.rs:31:20 | LL | const X_CORE: () = core::unimplemented!(); | -------------------^^^^^^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:39:20 + | the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:31:20 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: any use of this value will cause an error - --> $DIR/const_panic.rs:43:20 +error[E0080]: any use of this value will cause an error + --> $DIR/const_panic.rs:34:20 | LL | const W_CORE: () = core::panic!(MSG); | -------------------^^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'hello', $DIR/const_panic.rs:43:20 + | the evaluated program panicked at 'hello', $DIR/const_panic.rs:34:20 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 10 previous errors +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs b/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs index 0eb1e3eb94e..6b03e847def 100644 --- a/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs +++ b/src/test/ui/consts/const-eval/const_panic_libcore_bin.rs @@ -8,15 +8,12 @@ use core::panic::PanicInfo; const Z: () = panic!("cheese"); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out const Y: () = unreachable!(); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out const X: () = unimplemented!(); //~^ ERROR any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out #[lang = "eh_personality"] fn eh() {} diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr b/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr index 9971559e33b..2a3ad3ca180 100644 --- a/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr +++ b/src/test/ui/consts/const-eval/const_panic_libcore_bin.stderr @@ -1,4 +1,4 @@ -error: any use of this value will cause an error +error[E0080]: any use of this value will cause an error --> $DIR/const_panic_libcore_bin.rs:9:15 | LL | const Z: () = panic!("cheese"); @@ -6,34 +6,28 @@ LL | const Z: () = panic!("cheese"); | | | the evaluated program panicked at 'cheese', $DIR/const_panic_libcore_bin.rs:9:15 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: any use of this value will cause an error - --> $DIR/const_panic_libcore_bin.rs:13:15 +error[E0080]: any use of this value will cause an error + --> $DIR/const_panic_libcore_bin.rs:12:15 | LL | const Y: () = unreachable!(); | --------------^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:13:15 + | the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_libcore_bin.rs:12:15 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: any use of this value will cause an error - --> $DIR/const_panic_libcore_bin.rs:17:15 +error[E0080]: any use of this value will cause an error + --> $DIR/const_panic_libcore_bin.rs:15:15 | LL | const X: () = unimplemented!(); | --------------^^^^^^^^^^^^^^^^- | | - | the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:17:15 + | the evaluated program panicked at 'not implemented', $DIR/const_panic_libcore_bin.rs:15:15 | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/issue-50814-2.stderr b/src/test/ui/consts/const-eval/issue-50814-2.stderr index 0c520165496..d34ac773da2 100644 --- a/src/test/ui/consts/const-eval/issue-50814-2.stderr +++ b/src/test/ui/consts/const-eval/issue-50814-2.stderr @@ -10,7 +10,7 @@ LL | const BAR: usize = [5, 6, 7][T::BOO]; = 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[E0080]: evaluation of constant value failed +error[E0080]: evaluation of `foo::<()>` failed --> $DIR/issue-50814-2.rs:19:6 | LL | &<A<T> as Foo<T>>::BAR diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr index cf82d1eef3e..dd8d6bf839a 100644 --- a/src/test/ui/consts/const-eval/issue-50814.stderr +++ b/src/test/ui/consts/const-eval/issue-50814.stderr @@ -10,7 +10,7 @@ LL | const MAX: u8 = A::MAX + B::MAX; = 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[E0080]: evaluation of constant value failed +error[E0080]: evaluation of `foo::<i32>` failed --> $DIR/issue-50814.rs:21:6 | LL | &Sum::<U8,U8>::MAX diff --git a/src/test/ui/consts/const-eval/issue-85155.rs b/src/test/ui/consts/const-eval/issue-85155.rs new file mode 100644 index 00000000000..c3216d53d05 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-85155.rs @@ -0,0 +1,21 @@ +// This is a test with a setup similar to issue 85155, which triggers a const eval error: a const +// argument value is outside the range expected by the `stdarch` intrinsic. +// +// It's not the exact code mentioned in that issue because it depends both on `stdarch` intrinsics +// only available on x64, and internal implementation details of `stdarch`. But mostly because these +// are not important to trigger the diagnostics issue: it's specifically about the lack of context +// in the diagnostics of post-monomorphization errors (PMEs) for consts, happening in a dependency. +// Therefore, its setup is reproduced with an aux crate, which will similarly trigger a PME +// depending on the const argument value, like the `stdarch` intrinsics would. +// +// aux-build: post_monomorphization_error.rs +// build-fail: this is a post-monomorphization error, it passes check runs and requires building +// to actually fail. + +extern crate post_monomorphization_error; + +fn main() { + // This function triggers a PME whenever the const argument does not fit in 1-bit. + post_monomorphization_error::stdarch_intrinsic::<2>(); + //~^ NOTE the above error was encountered while instantiating +} diff --git a/src/test/ui/consts/const-eval/issue-85155.stderr b/src/test/ui/consts/const-eval/issue-85155.stderr new file mode 100644 index 00000000000..c36d7c17215 --- /dev/null +++ b/src/test/ui/consts/const-eval/issue-85155.stderr @@ -0,0 +1,15 @@ +error[E0080]: evaluation of `post_monomorphization_error::ValidateConstImm::<2_i32, 0_i32, 1_i32>::VALID` failed + --> $DIR/auxiliary/post_monomorphization_error.rs:7:17 + | +LL | let _ = 1 / ((IMM >= MIN && IMM <= MAX) as usize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to divide `1_usize` by zero + +note: the above error was encountered while instantiating `fn post_monomorphization_error::stdarch_intrinsic::<2_i32>` + --> $DIR/issue-85155.rs:19:5 + | +LL | post_monomorphization_error::stdarch_intrinsic::<2>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs index f76440298b3..dd18a98035b 100644 --- a/src/test/ui/consts/const-eval/panic-assoc-never-type.rs +++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.rs @@ -9,8 +9,7 @@ struct PrintName; impl PrintName { const VOID: ! = panic!(); - //~^ WARN any use of this value will cause an error - //~| WARN this was previously accepted by the compiler but is being phased out + //~^ ERROR any use of this value will cause an error } fn main() { diff --git a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr index d1f067df848..e186240f53a 100644 --- a/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr +++ b/src/test/ui/consts/const-eval/panic-assoc-never-type.stderr @@ -1,4 +1,4 @@ -warning: any use of this value will cause an error +error[E0080]: any use of this value will cause an error --> $DIR/panic-assoc-never-type.rs:11:21 | LL | const VOID: ! = panic!(); @@ -6,21 +6,14 @@ LL | const VOID: ! = panic!(); | | | the evaluated program panicked at 'explicit panic', $DIR/panic-assoc-never-type.rs:11:21 | -note: the lint level is defined here - --> $DIR/panic-assoc-never-type.rs:4:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ - = 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> - = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: erroneous constant used - --> $DIR/panic-assoc-never-type.rs:17:13 + --> $DIR/panic-assoc-never-type.rs:16:13 | LL | let _ = PrintName::VOID; | ^^^^^^^^^^^^^^^ referenced constant has errors -error: aborting due to previous error; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/panic-never-type.rs b/src/test/ui/consts/const-eval/panic-never-type.rs index c5139c575b1..71b489d828c 100644 --- a/src/test/ui/consts/const-eval/panic-never-type.rs +++ b/src/test/ui/consts/const-eval/panic-never-type.rs @@ -1,15 +1,11 @@ -// build-fail - // Regression test for #66975 #![warn(const_err)] #![feature(const_panic)] #![feature(never_type)] const VOID: ! = panic!(); -//~^ WARN any use of this value will cause an error -//~| WARN this was previously accepted by the compiler but is being phased out +//~^ ERROR any use of this value will cause an error fn main() { let _ = VOID; - //~^ ERROR erroneous constant used } diff --git a/src/test/ui/consts/const-eval/panic-never-type.stderr b/src/test/ui/consts/const-eval/panic-never-type.stderr index 2217bf1e05a..2254c3dcfdf 100644 --- a/src/test/ui/consts/const-eval/panic-never-type.stderr +++ b/src/test/ui/consts/const-eval/panic-never-type.stderr @@ -1,26 +1,13 @@ -warning: any use of this value will cause an error - --> $DIR/panic-never-type.rs:8:17 +error[E0080]: any use of this value will cause an error + --> $DIR/panic-never-type.rs:6:17 | LL | const VOID: ! = panic!(); | ----------------^^^^^^^^- | | - | the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:8:17 + | the evaluated program panicked at 'explicit panic', $DIR/panic-never-type.rs:6:17 | -note: the lint level is defined here - --> $DIR/panic-never-type.rs:4:9 - | -LL | #![warn(const_err)] - | ^^^^^^^^^ - = 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> - = note: this warning originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0080]: erroneous constant used - --> $DIR/panic-never-type.rs:13:13 - | -LL | let _ = VOID; - | ^^^^ referenced constant has errors + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/unwind-abort.rs b/src/test/ui/consts/const-eval/unwind-abort.rs index 10820986fa7..9bc63d9328c 100644 --- a/src/test/ui/consts/const-eval/unwind-abort.rs +++ b/src/test/ui/consts/const-eval/unwind-abort.rs @@ -2,8 +2,7 @@ #[unwind(aborts)] const fn foo() { - panic!() //~ ERROR any use of this value will cause an error [const_err] - //~| WARN this was previously accepted by the compiler but is being phased out + panic!() //~ ERROR any use of this value will cause an error } const _: () = foo(); diff --git a/src/test/ui/consts/const-eval/unwind-abort.stderr b/src/test/ui/consts/const-eval/unwind-abort.stderr index 79fdd05be30..b41d786169b 100644 --- a/src/test/ui/consts/const-eval/unwind-abort.stderr +++ b/src/test/ui/consts/const-eval/unwind-abort.stderr @@ -1,4 +1,4 @@ -error: any use of this value will cause an error +error[E0080]: any use of this value will cause an error --> $DIR/unwind-abort.rs:5:5 | LL | panic!() @@ -6,15 +6,13 @@ LL | panic!() | | | the evaluated program panicked at 'explicit panic', $DIR/unwind-abort.rs:5:5 | inside `foo` at $SRC_DIR/std/src/panic.rs:LL:COL - | inside `_` at $DIR/unwind-abort.rs:9:15 + | inside `_` at $DIR/unwind-abort.rs:8:15 ... LL | const _: () = foo(); | -------------------- | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs index 1ce78147970..031e67a1e3c 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.rs @@ -9,5 +9,5 @@ fn main() { let a: [u8; foo()]; //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block foo(); - //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block + //[mir]~^ ERROR call to unsafe function is unsafe and requires unsafe function or block } diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr index b643ecc0ce8..c6077da768b 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-requires-unsafe.thir.stderr @@ -1,12 +1,4 @@ error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/const-extern-fn-requires-unsafe.rs:11:5 - | -LL | foo(); - | ^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - -error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/const-extern-fn-requires-unsafe.rs:9:17 | LL | let a: [u8; foo()]; @@ -14,6 +6,6 @@ LL | let a: [u8; foo()]; | = note: consult the function's documentation for information on how to avoid undefined behavior -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/consts/const-unwrap.stderr b/src/test/ui/consts/const-unwrap.stderr index 0100dce5a96..95f4711cb65 100644 --- a/src/test/ui/consts/const-unwrap.stderr +++ b/src/test/ui/consts/const-unwrap.stderr @@ -1,4 +1,4 @@ -error: any use of this value will cause an error +error[E0080]: any use of this value will cause an error --> $SRC_DIR/core/src/option.rs:LL:COL | LL | None => panic!("called `Option::unwrap()` on a `None` value"), @@ -13,10 +13,8 @@ LL | None => panic!("called `Option::unwrap()` on a `None` value"), LL | const BAR: i32 = Option::<i32>::None.unwrap(); | ---------------------------------------------- | - = 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> = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const_fn_unsize.gated.stderr b/src/test/ui/consts/const_fn_unsize.gated.stderr deleted file mode 100644 index 8a65c274ca9..00000000000 --- a/src/test/ui/consts/const_fn_unsize.gated.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: fatal error triggered by #[rustc_error] - --> $DIR/const_fn_unsize.rs:16:1 - | -LL | fn main() {} - | ^^^^^^^^^ - -error: aborting due to previous error - diff --git a/src/test/ui/consts/const_fn_unsize.rs b/src/test/ui/consts/const_fn_unsize.rs index 0cab3b0a031..01da57320c2 100644 --- a/src/test/ui/consts/const_fn_unsize.rs +++ b/src/test/ui/consts/const_fn_unsize.rs @@ -1,16 +1,21 @@ -// gate-test-const_fn_unsize - -// revisions: stock gated - -#![feature(rustc_attrs)] -#![cfg_attr(gated, feature(const_fn_unsize))] +// run-pass +#![feature(slice_ptr_len)] use std::ptr::NonNull; +#[allow(unused)] const fn test() { let _x = NonNull::<[i32; 0]>::dangling() as NonNull<[i32]>; - //[stock]~^ unsizing cast } -#[rustc_error] -fn main() {} //[gated]~ fatal error triggered by #[rustc_error] +// Regression test for #75118. +pub const fn dangling_slice<T>() -> NonNull<[T]> { + NonNull::<[T; 1]>::dangling() +} + +const C: NonNull<[i32]> = dangling_slice(); + +fn main() { + assert_eq!(C.as_ptr(), NonNull::<[i32; 1]>::dangling().as_ptr() as *mut _); + assert_eq!(C.as_ptr().len(), 1); +} diff --git a/src/test/ui/consts/const_fn_unsize.stock.stderr b/src/test/ui/consts/const_fn_unsize.stock.stderr deleted file mode 100644 index cc746d4f175..00000000000 --- a/src/test/ui/consts/const_fn_unsize.stock.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: unsizing casts to types besides slices are not allowed in const fn - --> $DIR/const_fn_unsize.rs:11:14 - | -LL | let _x = NonNull::<[i32; 0]>::dangling() as NonNull<[i32]>; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information - = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/control-flow/assert.const_panic.stderr b/src/test/ui/consts/control-flow/assert.const_panic.stderr index 665b4240011..8e1a2b5eb46 100644 --- a/src/test/ui/consts/control-flow/assert.const_panic.stderr +++ b/src/test/ui/consts/control-flow/assert.const_panic.stderr @@ -1,4 +1,4 @@ -error: any use of this value will cause an error +error[E0080]: any use of this value will cause an error --> $DIR/assert.rs:10:15 | LL | const _: () = assert!(false); @@ -6,10 +6,8 @@ LL | const _: () = assert!(false); | | | the evaluated program panicked at 'assertion failed: false', $DIR/assert.rs:10:15 | - = 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> = note: this error originates in the macro `assert` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/control-flow/assert.rs b/src/test/ui/consts/control-flow/assert.rs index a21f28604bd..90017fee193 100644 --- a/src/test/ui/consts/control-flow/assert.rs +++ b/src/test/ui/consts/control-flow/assert.rs @@ -10,6 +10,5 @@ const _: () = assert!(true); const _: () = assert!(false); //[stock]~^ ERROR panicking in constants is unstable //[const_panic]~^^ ERROR any use of this value will cause an error -//[const_panic]~| WARN this was previously accepted by the compiler but is being phased out fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index e46127c36bf..b7904e6841b 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -133,13 +133,13 @@ const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~^ ERROR trait bounds other than `Sized` const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~^ ERROR trait bounds other than `Sized` -//~| ERROR unsizing cast -//~| ERROR unsizing cast const fn no_unsafe() { unsafe {} } const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } -//~^ ERROR unsizing cast +//~^ ERROR trait bounds other than `Sized` +//~| ERROR trait bounds other than `Sized` +//~| ERROR trait bounds other than `Sized` const fn no_fn_ptrs(_x: fn()) {} //~^ ERROR function pointer diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index e6ce7e12520..d31d4121936 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -288,32 +288,32 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: unsizing casts to types besides slices are not allowed in const fn - --> $DIR/min_const_fn.rs:134:63 +error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:139:41 | -LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } - | ^^^ +LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information - = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable + = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information + = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: unsizing casts to types besides slices are not allowed in const fn - --> $DIR/min_const_fn.rs:134:63 +error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:139:42 | -LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } - | ^^^ +LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information - = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable + = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information + = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: unsizing casts to types besides slices are not allowed in const fn - --> $DIR/min_const_fn.rs:141:42 +error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable + --> $DIR/min_const_fn.rs:139:42 | LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } - | ^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information - = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable + = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information + = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable error[E0658]: function pointers cannot appear in constant functions --> $DIR/min_const_fn.rs:144:21 diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs index 4a22ef2dffd..6ca1e59b3af 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs @@ -10,6 +10,6 @@ const fn no_inner_dyn_trait2(x: Hide) { //~^ ERROR trait bounds other than `Sized` } const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } -//~^ ERROR unsizing cast +//~^ ERROR trait bounds other than `Sized` fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr index cf635d65699..ce844a2f071 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr @@ -7,14 +7,14 @@ LL | x.0.field; = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable -error[E0658]: unsizing casts to types besides slices are not allowed in const fn +error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn_dyn.rs:12:66 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } | ^^ | - = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information - = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable + = note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information + = help: add `#![feature(const_fn_trait_bound)]` to the crate attributes to enable error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/miri_unleashed/tls.stderr b/src/test/ui/consts/miri_unleashed/tls.stderr index 62e2dc71210..30309da499f 100644 --- a/src/test/ui/consts/miri_unleashed/tls.stderr +++ b/src/test/ui/consts/miri_unleashed/tls.stderr @@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:12:25 | LL | unsafe { let _val = A; } - | ^ cannot access thread local static (DefId(0:6 ~ tls[317d]::A)) + | ^ cannot access thread local static (DefId(0:6 ~ tls[f423]::A)) error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:19:26 | LL | unsafe { let _val = &A; } - | ^ cannot access thread local static (DefId(0:6 ~ tls[317d]::A)) + | ^ cannot access thread local static (DefId(0:6 ~ tls[f423]::A)) warning: skipping const checks | diff --git a/src/test/ui/consts/unsizing-cast-non-null.rs b/src/test/ui/consts/unsizing-cast-non-null.rs deleted file mode 100644 index af6bc2d85fd..00000000000 --- a/src/test/ui/consts/unsizing-cast-non-null.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Regression test for #75118. - -use std::ptr::NonNull; - -pub const fn dangling_slice<T>() -> NonNull<[T]> { - NonNull::<[T; 0]>::dangling() - //~^ ERROR: unsizing casts to types besides slices -} - -fn main() {} diff --git a/src/test/ui/consts/unsizing-cast-non-null.stderr b/src/test/ui/consts/unsizing-cast-non-null.stderr deleted file mode 100644 index 79691cddfb4..00000000000 --- a/src/test/ui/consts/unsizing-cast-non-null.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: unsizing casts to types besides slices are not allowed in const fn - --> $DIR/unsizing-cast-non-null.rs:6:5 - | -LL | NonNull::<[T; 0]>::dangling() - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #64992 <https://github.com/rust-lang/rust/issues/64992> for more information - = help: add `#![feature(const_fn_unsize)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/dep-graph/dep-graph-check-attr.rs b/src/test/ui/dep-graph/dep-graph-check-attr.rs index 1026efc1b1d..a45bf24f8c1 100644 --- a/src/test/ui/dep-graph/dep-graph-check-attr.rs +++ b/src/test/ui/dep-graph/dep-graph-check-attr.rs @@ -5,7 +5,7 @@ #![allow(dead_code)] #![allow(unused_variables)] -#[rustc_dirty(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph +#[rustc_clean(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph fn main() {} #[rustc_if_this_changed(hir_owner)] //~ ERROR attribute requires -Z query-dep-graph diff --git a/src/test/ui/dep-graph/dep-graph-check-attr.stderr b/src/test/ui/dep-graph/dep-graph-check-attr.stderr index 945a4237c12..46f4e4358cf 100644 --- a/src/test/ui/dep-graph/dep-graph-check-attr.stderr +++ b/src/test/ui/dep-graph/dep-graph-check-attr.stderr @@ -1,7 +1,7 @@ error: attribute requires -Z query-dep-graph to be enabled --> $DIR/dep-graph-check-attr.rs:8:1 | -LL | #[rustc_dirty(hir_owner)] +LL | #[rustc_clean(hir_owner)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: attribute requires -Z query-dep-graph to be enabled diff --git a/src/test/ui/deprecation/deprecation-lint.stderr b/src/test/ui/deprecation/deprecation-lint.stderr index 3699a939e27..20af4f62e65 100644 --- a/src/test/ui/deprecation/deprecation-lint.stderr +++ b/src/test/ui/deprecation/deprecation-lint.stderr @@ -11,16 +11,16 @@ LL | #![deny(deprecated)] | ^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:21:9 + --> $DIR/deprecation-lint.rs:21:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:23:9 + --> $DIR/deprecation-lint.rs:23:25 | LL | <Foo as Trait>::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated function `deprecation_lint::deprecated_text`: text --> $DIR/deprecation-lint.rs:25:9 @@ -29,16 +29,16 @@ LL | deprecated_text(); | ^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:30:9 + --> $DIR/deprecation-lint.rs:30:16 | LL | ... Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:32:9 + --> $DIR/deprecation-lint.rs:32:25 | LL | ... <Foo as Trait>::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated struct `deprecation_lint::DeprecatedStruct`: text --> $DIR/deprecation-lint.rs:34:17 @@ -53,10 +53,10 @@ LL | let _ = DeprecatedUnitStruct; | ^^^^^^^^^^^^^^^^^^^^ error: use of deprecated variant `deprecation_lint::Enum::DeprecatedVariant`: text - --> $DIR/deprecation-lint.rs:40:17 + --> $DIR/deprecation-lint.rs:40:23 | LL | let _ = Enum::DeprecatedVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: use of deprecated struct `deprecation_lint::DeprecatedTupleStruct`: text --> $DIR/deprecation-lint.rs:42:17 @@ -65,28 +65,28 @@ LL | let _ = DeprecatedTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated struct `deprecation_lint::nested::DeprecatedStruct`: text - --> $DIR/deprecation-lint.rs:44:17 + --> $DIR/deprecation-lint.rs:44:25 | LL | let _ = nested::DeprecatedStruct { - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated struct `deprecation_lint::nested::DeprecatedUnitStruct`: text - --> $DIR/deprecation-lint.rs:48:17 + --> $DIR/deprecation-lint.rs:48:25 | LL | let _ = nested::DeprecatedUnitStruct; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: use of deprecated variant `deprecation_lint::nested::Enum::DeprecatedVariant`: text - --> $DIR/deprecation-lint.rs:50:17 + --> $DIR/deprecation-lint.rs:50:31 | LL | ... let _ = nested::Enum::DeprecatedVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: use of deprecated struct `deprecation_lint::nested::DeprecatedTupleStruct`: text - --> $DIR/deprecation-lint.rs:52:17 + --> $DIR/deprecation-lint.rs:52:25 | LL | ... let _ = nested::DeprecatedTupleStruct (1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated function `deprecation_lint::deprecated_text`: text --> $DIR/deprecation-lint.rs:59:25 @@ -101,28 +101,28 @@ LL | macro_test_arg!(macro_test_arg!(deprecated_text())); | ^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:65:9 + --> $DIR/deprecation-lint.rs:65:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:67:9 + --> $DIR/deprecation-lint.rs:67:25 | LL | <Foo as Trait>::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:69:9 + --> $DIR/deprecation-lint.rs:69:16 | LL | ... Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated associated function `deprecation_lint::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:71:9 + --> $DIR/deprecation-lint.rs:71:25 | LL | ... <Foo as Trait>::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated trait `deprecation_lint::DeprecatedTrait`: text --> $DIR/deprecation-lint.rs:81:10 @@ -173,10 +173,10 @@ LL | let Deprecated2 | ^^^^^^^^^^^ error: use of deprecated function `deprecation_lint::deprecated_mod::deprecated`: text - --> $DIR/deprecation-lint.rs:162:9 + --> $DIR/deprecation-lint.rs:162:25 | LL | deprecated_mod::deprecated(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ error: use of deprecated function `this_crate::deprecated`: text --> $DIR/deprecation-lint.rs:245:9 @@ -185,16 +185,16 @@ LL | deprecated(); | ^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:250:9 + --> $DIR/deprecation-lint.rs:250:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:252:9 + --> $DIR/deprecation-lint.rs:252:25 | LL | <Foo as Trait>::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated function `this_crate::deprecated_text`: text --> $DIR/deprecation-lint.rs:254:9 @@ -203,16 +203,16 @@ LL | deprecated_text(); | ^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:259:9 + --> $DIR/deprecation-lint.rs:259:16 | LL | Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:261:9 + --> $DIR/deprecation-lint.rs:261:25 | LL | ... <Foo as Trait>::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated function `this_crate::deprecated_future`: text --> $DIR/deprecation-lint.rs:264:9 @@ -239,10 +239,10 @@ LL | let _ = DeprecatedUnitStruct; | ^^^^^^^^^^^^^^^^^^^^ error: use of deprecated unit variant `this_crate::Enum::DeprecatedVariant`: text - --> $DIR/deprecation-lint.rs:274:17 + --> $DIR/deprecation-lint.rs:274:23 | LL | let _ = Enum::DeprecatedVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: use of deprecated tuple struct `this_crate::DeprecatedTupleStruct`: text --> $DIR/deprecation-lint.rs:276:17 @@ -251,52 +251,52 @@ LL | let _ = DeprecatedTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated struct `this_crate::nested::DeprecatedStruct`: text - --> $DIR/deprecation-lint.rs:278:17 + --> $DIR/deprecation-lint.rs:278:25 | LL | let _ = nested::DeprecatedStruct { - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated unit struct `this_crate::nested::DeprecatedUnitStruct`: text - --> $DIR/deprecation-lint.rs:283:17 + --> $DIR/deprecation-lint.rs:283:25 | LL | let _ = nested::DeprecatedUnitStruct; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ error: use of deprecated unit variant `this_crate::nested::Enum::DeprecatedVariant`: text - --> $DIR/deprecation-lint.rs:285:17 + --> $DIR/deprecation-lint.rs:285:31 | LL | ... let _ = nested::Enum::DeprecatedVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ error: use of deprecated tuple struct `this_crate::nested::DeprecatedTupleStruct`: text - --> $DIR/deprecation-lint.rs:287:17 + --> $DIR/deprecation-lint.rs:287:25 | LL | ... let _ = nested::DeprecatedTupleStruct (1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:292:9 + --> $DIR/deprecation-lint.rs:292:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/deprecation-lint.rs:294:9 + --> $DIR/deprecation-lint.rs:294:25 | LL | <Foo as Trait>::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:296:9 + --> $DIR/deprecation-lint.rs:296:16 | LL | Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/deprecation-lint.rs:298:9 + --> $DIR/deprecation-lint.rs:298:25 | LL | ... <Foo as Trait>::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ error: use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar` --> $DIR/deprecation-lint.rs:316:13 diff --git a/src/test/ui/deprecation/suggestion.fixed b/src/test/ui/deprecation/suggestion.fixed index eba72f88a89..1ba1821e6c1 100644 --- a/src/test/ui/deprecation/suggestion.fixed +++ b/src/test/ui/deprecation/suggestion.fixed @@ -1,9 +1,7 @@ // run-rustfix #![feature(staged_api)] - #![stable(since = "1.0.0", feature = "test")] - #![deny(deprecated)] #![allow(dead_code)] @@ -21,8 +19,21 @@ impl Foo { fn replacement(&self) {} } +mod bar { + #[rustc_deprecated( + since = "1.0.0", + reason = "replaced by `replacement`", + suggestion = "replacement", + )] + #[stable(since = "1.0.0", feature = "test")] + pub fn deprecated() {} + + pub fn replacement() {} +} + fn main() { let foo = Foo; - foo.replacement(); //~ ERROR use of deprecated + + bar::replacement(); //~ ERROR use of deprecated } diff --git a/src/test/ui/deprecation/suggestion.rs b/src/test/ui/deprecation/suggestion.rs index 8f9791c13e8..e40737d1957 100644 --- a/src/test/ui/deprecation/suggestion.rs +++ b/src/test/ui/deprecation/suggestion.rs @@ -1,9 +1,7 @@ // run-rustfix #![feature(staged_api)] - #![stable(since = "1.0.0", feature = "test")] - #![deny(deprecated)] #![allow(dead_code)] @@ -21,8 +19,21 @@ impl Foo { fn replacement(&self) {} } +mod bar { + #[rustc_deprecated( + since = "1.0.0", + reason = "replaced by `replacement`", + suggestion = "replacement", + )] + #[stable(since = "1.0.0", feature = "test")] + pub fn deprecated() {} + + pub fn replacement() {} +} + fn main() { let foo = Foo; - foo.deprecated(); //~ ERROR use of deprecated + + bar::deprecated(); //~ ERROR use of deprecated } diff --git a/src/test/ui/deprecation/suggestion.stderr b/src/test/ui/deprecation/suggestion.stderr index 8a7cb1def90..b95ca3a75e4 100644 --- a/src/test/ui/deprecation/suggestion.stderr +++ b/src/test/ui/deprecation/suggestion.stderr @@ -1,14 +1,20 @@ -error: use of deprecated associated function `Foo::deprecated`: replaced by `replacement` - --> $DIR/suggestion.rs:27:9 +error: use of deprecated function `bar::deprecated`: replaced by `replacement` + --> $DIR/suggestion.rs:38:10 | -LL | foo.deprecated(); - | ^^^^^^^^^^ help: replace the use of the deprecated associated function: `replacement` +LL | bar::deprecated(); + | ^^^^^^^^^^ help: replace the use of the deprecated function: `replacement` | note: the lint level is defined here - --> $DIR/suggestion.rs:7:9 + --> $DIR/suggestion.rs:5:9 | LL | #![deny(deprecated)] | ^^^^^^^^^^ -error: aborting due to previous error +error: use of deprecated associated function `Foo::deprecated`: replaced by `replacement` + --> $DIR/suggestion.rs:36:9 + | +LL | foo.deprecated(); + | ^^^^^^^^^^ help: replace the use of the deprecated associated function: `replacement` + +error: aborting due to 2 previous errors diff --git a/src/test/ui/derives/derive-macro-const-default.rs b/src/test/ui/derives/derive-macro-const-default.rs index a844f2d2023..7c4ebca8746 100644 --- a/src/test/ui/derives/derive-macro-const-default.rs +++ b/src/test/ui/derives/derive-macro-const-default.rs @@ -1,5 +1,4 @@ // check-pass -#![allow(incomplete_features)] #![feature(const_generics_defaults)] #[derive(Clone, PartialEq, Debug)] diff --git a/src/test/ui/error-codes/E0107.rs b/src/test/ui/error-codes/E0107.rs index f7f6afa860e..840700c9cc6 100644 --- a/src/test/ui/error-codes/E0107.rs +++ b/src/test/ui/error-codes/E0107.rs @@ -1,5 +1,7 @@ struct Foo<'a>(&'a str); struct Buzz<'a, 'b>(&'a str, &'b str); +struct Qux<'a, T>(&'a T); +struct Quux<T>(T); enum Bar { A, @@ -19,6 +21,30 @@ struct Baz<'a, 'b, 'c> { foo2: Foo<'a, 'b, 'c>, //~^ ERROR this struct takes 1 lifetime argument //~| HELP remove these lifetime arguments + + qux1: Qux<'a, 'b, i32>, + //~^ ERROR this struct takes 1 lifetime argument + //~| HELP remove this lifetime argument + + qux2: Qux<'a, i32, 'b>, + //~^ ERROR this struct takes 1 lifetime argument + //~| HELP remove this lifetime argument + + qux3: Qux<'a, 'b, 'c, i32>, + //~^ ERROR this struct takes 1 lifetime argument + //~| HELP remove these lifetime arguments + + qux4: Qux<'a, i32, 'b, 'c>, + //~^ ERROR this struct takes 1 lifetime argument + //~| HELP remove these lifetime arguments + + qux5: Qux<'a, 'b, i32, 'c>, + //~^ ERROR this struct takes 1 lifetime argument + //~| HELP remove this lifetime argument + + quux: Quux<'a, i32, 'b>, + //~^ ERROR this struct takes 0 lifetime arguments + //~| HELP remove this lifetime argument } fn main() {} diff --git a/src/test/ui/error-codes/E0107.stderr b/src/test/ui/error-codes/E0107.stderr index 299776b08f2..3c7aa6de541 100644 --- a/src/test/ui/error-codes/E0107.stderr +++ b/src/test/ui/error-codes/E0107.stderr @@ -1,5 +1,5 @@ error[E0107]: this struct takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/E0107.rs:11:11 + --> $DIR/E0107.rs:13:11 | LL | buzz: Buzz<'a>, | ^^^^ -- supplied 1 lifetime argument @@ -17,7 +17,7 @@ LL | buzz: Buzz<'a, 'a>, | ^^^^ error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/E0107.rs:15:10 + --> $DIR/E0107.rs:17:10 | LL | bar: Bar<'a>, | ^^^---- help: remove these generics @@ -25,13 +25,13 @@ LL | bar: Bar<'a>, | expected 0 lifetime arguments | note: enum defined here, with 0 lifetime parameters - --> $DIR/E0107.rs:4:6 + --> $DIR/E0107.rs:6:6 | LL | enum Bar { | ^^^ error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied - --> $DIR/E0107.rs:19:11 + --> $DIR/E0107.rs:21:11 | LL | foo2: Foo<'a, 'b, 'c>, | ^^^ ------ help: remove these lifetime arguments @@ -44,6 +44,90 @@ note: struct defined here, with 1 lifetime parameter: `'a` LL | struct Foo<'a>(&'a str); | ^^^ -- -error: aborting due to 3 previous errors +error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied + --> $DIR/E0107.rs:25:11 + | +LL | qux1: Qux<'a, 'b, i32>, + | ^^^ -- help: remove this lifetime argument + | | + | expected 1 lifetime argument + | +note: struct defined here, with 1 lifetime parameter: `'a` + --> $DIR/E0107.rs:3:8 + | +LL | struct Qux<'a, T>(&'a T); + | ^^^ -- + +error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied + --> $DIR/E0107.rs:29:11 + | +LL | qux2: Qux<'a, i32, 'b>, + | ^^^ -- help: remove this lifetime argument + | | + | expected 1 lifetime argument + | +note: struct defined here, with 1 lifetime parameter: `'a` + --> $DIR/E0107.rs:3:8 + | +LL | struct Qux<'a, T>(&'a T); + | ^^^ -- + +error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied + --> $DIR/E0107.rs:33:11 + | +LL | qux3: Qux<'a, 'b, 'c, i32>, + | ^^^ ------ help: remove these lifetime arguments + | | + | expected 1 lifetime argument + | +note: struct defined here, with 1 lifetime parameter: `'a` + --> $DIR/E0107.rs:3:8 + | +LL | struct Qux<'a, T>(&'a T); + | ^^^ -- + +error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied + --> $DIR/E0107.rs:37:11 + | +LL | qux4: Qux<'a, i32, 'b, 'c>, + | ^^^ ------ help: remove these lifetime arguments + | | + | expected 1 lifetime argument + | +note: struct defined here, with 1 lifetime parameter: `'a` + --> $DIR/E0107.rs:3:8 + | +LL | struct Qux<'a, T>(&'a T); + | ^^^ -- + +error[E0107]: this struct takes 1 lifetime argument but 3 lifetime arguments were supplied + --> $DIR/E0107.rs:41:11 + | +LL | qux5: Qux<'a, 'b, i32, 'c>, + | ^^^ -- help: remove this lifetime argument + | | + | expected 1 lifetime argument + | +note: struct defined here, with 1 lifetime parameter: `'a` + --> $DIR/E0107.rs:3:8 + | +LL | struct Qux<'a, T>(&'a T); + | ^^^ -- + +error[E0107]: this struct takes 0 lifetime arguments but 2 lifetime arguments were supplied + --> $DIR/E0107.rs:45:11 + | +LL | quux: Quux<'a, i32, 'b>, + | ^^^^ -- help: remove this lifetime argument + | | + | expected 0 lifetime arguments + | +note: struct defined here, with 0 lifetime parameters + --> $DIR/E0107.rs:4:8 + | +LL | struct Quux<T>(T); + | ^^^^ + +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr index 43269c095d6..6314e7a3a8a 100644 --- a/src/test/ui/error-codes/E0605.stderr +++ b/src/test/ui/error-codes/E0605.stderr @@ -8,7 +8,12 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8` --> $DIR/E0605.rs:6:5 | LL | v as &u8; - | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | ^^^^^^^^ invalid cast + | +help: consider borrowing the value + | +LL | &*v as &u8; + | ^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr index 04efea0b230..df0de7a9590 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.thir.stderr @@ -58,6 +58,14 @@ LL | const unsafe fn unsafe_transmute_fn_core_intrinsic() -> u32 { core::intrins = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable = note: `transmute` is only allowed in constants and statics for now +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/feature-gate-const_fn_transmute.rs:29:39 + | +LL | const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } + | ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:29:39 | @@ -68,49 +76,41 @@ LL | const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable = note: `transmute` is only allowed in constants and statics for now -error[E0658]: `transmute` is not allowed in constant functions +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/feature-gate-const_fn_transmute.rs:33:49 | LL | const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function | - = note: see issue #53605 <https://github.com/rust-lang/rust/issues/53605> for more information - = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable - = note: `transmute` is only allowed in constants and statics for now + = note: consult the function's documentation for information on how to avoid undefined behavior error[E0658]: `transmute` is not allowed in constant functions - --> $DIR/feature-gate-const_fn_transmute.rs:37:54 + --> $DIR/feature-gate-const_fn_transmute.rs:33:49 | -LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: see issue #53605 <https://github.com/rust-lang/rust/issues/53605> for more information = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable = note: `transmute` is only allowed in constants and statics for now error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/feature-gate-const_fn_transmute.rs:29:39 - | -LL | const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } - | ^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function - | - = note: consult the function's documentation for information on how to avoid undefined behavior - -error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/feature-gate-const_fn_transmute.rs:33:49 + --> $DIR/feature-gate-const_fn_transmute.rs:37:54 | -LL | const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function +LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function | = note: consult the function's documentation for information on how to avoid undefined behavior -error[E0133]: call to unsafe function is unsafe and requires unsafe function or block +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:37:54 | LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to unsafe function + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: consult the function's documentation for information on how to avoid undefined behavior + = note: see issue #53605 <https://github.com/rust-lang/rust/issues/53605> for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now error: aborting due to 12 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs deleted file mode 100644 index f19fdb45f1f..00000000000 --- a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[cfg(FALSE)] -#[attr = multi::segment::path] //~ ERROR arbitrary expressions in key-value attributes are unstable -#[attr = macro_call!()] //~ ERROR arbitrary expressions in key-value attributes are unstable -#[attr = 1 + 2] //~ ERROR arbitrary expressions in key-value attributes are unstable -#[attr = what?] //~ ERROR arbitrary expressions in key-value attributes are unstable -struct S; - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr b/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr deleted file mode 100644 index 9887814b907..00000000000 --- a/src/test/ui/feature-gates/feature-gate-extended_key_value_attributes.stderr +++ /dev/null @@ -1,39 +0,0 @@ -error[E0658]: arbitrary expressions in key-value attributes are unstable - --> $DIR/feature-gate-extended_key_value_attributes.rs:2:10 - | -LL | #[attr = multi::segment::path] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #78835 <https://github.com/rust-lang/rust/issues/78835> for more information - = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable - -error[E0658]: arbitrary expressions in key-value attributes are unstable - --> $DIR/feature-gate-extended_key_value_attributes.rs:3:10 - | -LL | #[attr = macro_call!()] - | ^^^^^^^^^^^^^ - | - = note: see issue #78835 <https://github.com/rust-lang/rust/issues/78835> for more information - = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable - -error[E0658]: arbitrary expressions in key-value attributes are unstable - --> $DIR/feature-gate-extended_key_value_attributes.rs:4:10 - | -LL | #[attr = 1 + 2] - | ^^^^^ - | - = note: see issue #78835 <https://github.com/rust-lang/rust/issues/78835> for more information - = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable - -error[E0658]: arbitrary expressions in key-value attributes are unstable - --> $DIR/feature-gate-extended_key_value_attributes.rs:5:10 - | -LL | #[attr = what?] - | ^^^^^ - | - = note: see issue #78835 <https://github.com/rust-lang/rust/issues/78835> for more information - = help: add `#![feature(extended_key_value_attributes)]` to the crate attributes to enable - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.rs b/src/test/ui/feature-gates/feature-gate-member-constraints.rs deleted file mode 100644 index f6a92b0d0bf..00000000000 --- a/src/test/ui/feature-gates/feature-gate-member-constraints.rs +++ /dev/null @@ -1,10 +0,0 @@ -trait Trait<'a, 'b> {} -impl<T> Trait<'_, '_> for T {} - -fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> { - //~^ ERROR ambiguous lifetime bound - //~| ERROR ambiguous lifetime bound - (x, y) -} - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr b/src/test/ui/feature-gates/feature-gate-member-constraints.stderr deleted file mode 100644 index c2ec7ae16a3..00000000000 --- a/src/test/ui/feature-gates/feature-gate-member-constraints.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error: ambiguous lifetime bound in `impl Trait` - --> $DIR/feature-gate-member-constraints.rs:4:43 - | -LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> { - | ^^^^^^^^^^^^^^^^^^ neither `'a` nor `'b` outlives the other - | - = help: add #![feature(member_constraints)] to the crate attributes to enable - -error: ambiguous lifetime bound in `impl Trait` - --> $DIR/feature-gate-member-constraints.rs:4:43 - | -LL | fn foo<'a, 'b>(x: &'a u32, y: &'b u32) -> impl Trait<'a, 'b> { - | ^^^^^^^^^^^^^^^^^^ the elided lifetimes here do not outlive one another - | - = help: add #![feature(member_constraints)] to the crate attributes to enable - -error: aborting due to 2 previous errors - diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.stderr b/src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr index 0bd3dbf6863..3afbea07931 100644 --- a/src/test/ui/generator/issue-45729-unsafe-in-generator.stderr +++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/issue-45729-unsafe-in-generator.rs:5:9 + --> $DIR/issue-45729-unsafe-in-generator.rs:8:9 | LL | *(1 as *mut u32) = 42; | ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.rs b/src/test/ui/generator/issue-45729-unsafe-in-generator.rs index 638a1994bb5..379c36d2ca3 100644 --- a/src/test/ui/generator/issue-45729-unsafe-in-generator.rs +++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![feature(generators)] fn main() { diff --git a/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr b/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr new file mode 100644 index 00000000000..10d768f19fc --- /dev/null +++ b/src/test/ui/generator/issue-45729-unsafe-in-generator.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/issue-45729-unsafe-in-generator.rs:8:9 + | +LL | *(1 as *mut u32) = 42; + | ^^^^^^^^^^^^^^^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr index 78100318dc3..bd0d27ff3e9 100644 --- a/src/test/ui/generator/print/generator-print-verbose-1.stderr +++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr @@ -12,7 +12,7 @@ note: generator is not `Send` as this value is used across a yield --> $DIR/generator-print-verbose-1.rs:35:9 | LL | let _non_send_gen = make_non_send_generator(); - | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[317d]::make_non_send_generator::{opaque#0}), [])` which is not `Send` + | ------------- has type `Opaque(DefId(0:34 ~ generator_print_verbose_1[70c9]::make_non_send_generator::{opaque#0}), [])` which is not `Send` LL | yield; | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later LL | }; @@ -30,10 +30,10 @@ LL | require_send(send_gen); = help: the trait `Sync` is not implemented for `RefCell<i32>` = note: required because of the requirements on the impl of `Send` for `Arc<RefCell<i32>>` = note: required because it appears within the type `[make_gen2<Arc<RefCell<i32>>>::{closure#0} upvar_tys=(Arc<RefCell<i32>>) {()}]` - = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[317d]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])` - = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), [])` - = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}` - = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}]` + = note: required because it appears within the type `Opaque(DefId(0:39 ~ generator_print_verbose_1[70c9]::make_gen2::{opaque#0}), [std::sync::Arc<std::cell::RefCell<i32>>])` + = note: required because it appears within the type `Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), [])` + = note: required because it appears within the type `{Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), []), ()}` + = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:42 ~ generator_print_verbose_1[70c9]::make_non_send_generator2::{opaque#0}), []), ()}]` error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/static-mut-reference-across-yield.rs b/src/test/ui/generator/static-mut-reference-across-yield.rs index 2926bba9978..0fa6d9cdc77 100644 --- a/src/test/ui/generator/static-mut-reference-across-yield.rs +++ b/src/test/ui/generator/static-mut-reference-across-yield.rs @@ -1,4 +1,7 @@ // build-pass +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck + #![feature(generators)] static mut A: [i32; 5] = [1, 2, 3, 4, 5]; diff --git a/src/test/ui/generics/wrong-number-of-args.rs b/src/test/ui/generics/wrong-number-of-args.rs index ec2ed9926e2..272cd361968 100644 --- a/src/test/ui/generics/wrong-number-of-args.rs +++ b/src/test/ui/generics/wrong-number-of-args.rs @@ -66,6 +66,12 @@ mod lifetime_and_type { //~| ERROR missing lifetime specifier //~| HELP consider introducing //~| HELP add missing + + type F = Ty<'static, usize, 'static, usize>; + //~^ ERROR this struct takes 1 lifetime argument but 2 lifetime arguments + //~| ERROR this struct takes 1 generic argument but 2 generic arguments + //~| HELP remove this lifetime argument + //~| HELP remove this generic argument } mod type_and_type_and_type { diff --git a/src/test/ui/generics/wrong-number-of-args.stderr b/src/test/ui/generics/wrong-number-of-args.stderr index 17a924cedad..4e921db8c25 100644 --- a/src/test/ui/generics/wrong-number-of-args.stderr +++ b/src/test/ui/generics/wrong-number-of-args.stderr @@ -213,14 +213,42 @@ help: consider introducing a named lifetime parameter LL | type E<'a> = Ty<'a>; | ^^^^ ^^ +error[E0107]: this struct takes 1 lifetime argument but 2 lifetime arguments were supplied + --> $DIR/wrong-number-of-args.rs:70:14 + | +LL | type F = Ty<'static, usize, 'static, usize>; + | ^^ ------- help: remove this lifetime argument + | | + | expected 1 lifetime argument + | +note: struct defined here, with 1 lifetime parameter: `'a` + --> $DIR/wrong-number-of-args.rs:46:12 + | +LL | struct Ty<'a, T>; + | ^^ -- + +error[E0107]: this struct takes 1 generic argument but 2 generic arguments were supplied + --> $DIR/wrong-number-of-args.rs:70:14 + | +LL | type F = Ty<'static, usize, 'static, usize>; + | ^^ ----- help: remove this generic argument + | | + | expected 1 generic argument + | +note: struct defined here, with 1 generic parameter: `T` + --> $DIR/wrong-number-of-args.rs:46:12 + | +LL | struct Ty<'a, T>; + | ^^ - + error[E0107]: missing generics for struct `type_and_type_and_type::Ty` - --> $DIR/wrong-number-of-args.rs:74:14 + --> $DIR/wrong-number-of-args.rs:80:14 | LL | type A = Ty; | ^^ expected at least 2 generic arguments | note: struct defined here, with at least 2 generic parameters: `A`, `B` - --> $DIR/wrong-number-of-args.rs:72:12 + --> $DIR/wrong-number-of-args.rs:78:12 | LL | struct Ty<A, B, C = &'static str>; | ^^ - - @@ -230,7 +258,7 @@ LL | type A = Ty<A, B>; | ^^^^^^^^ error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:78:14 + --> $DIR/wrong-number-of-args.rs:84:14 | LL | type B = Ty<usize>; | ^^ ----- supplied 1 generic argument @@ -238,7 +266,7 @@ LL | type B = Ty<usize>; | expected at least 2 generic arguments | note: struct defined here, with at least 2 generic parameters: `A`, `B` - --> $DIR/wrong-number-of-args.rs:72:12 + --> $DIR/wrong-number-of-args.rs:78:12 | LL | struct Ty<A, B, C = &'static str>; | ^^ - - @@ -248,7 +276,7 @@ LL | type B = Ty<usize, B>; | ^^^ error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:86:14 + --> $DIR/wrong-number-of-args.rs:92:14 | LL | type E = Ty<usize, String, char, f64>; | ^^ --- help: remove this generic argument @@ -256,19 +284,19 @@ LL | type E = Ty<usize, String, char, f64>; | expected at most 3 generic arguments | note: struct defined here, with at most 3 generic parameters: `A`, `B`, `C` - --> $DIR/wrong-number-of-args.rs:72:12 + --> $DIR/wrong-number-of-args.rs:78:12 | LL | struct Ty<A, B, C = &'static str>; | ^^ - - - error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:90:14 + --> $DIR/wrong-number-of-args.rs:96:14 | LL | type F = Ty<>; | ^^ expected at least 2 generic arguments | note: struct defined here, with at least 2 generic parameters: `A`, `B` - --> $DIR/wrong-number-of-args.rs:72:12 + --> $DIR/wrong-number-of-args.rs:78:12 | LL | struct Ty<A, B, C = &'static str>; | ^^ - - @@ -278,7 +306,7 @@ LL | type F = Ty<A, B>; | ^^^^ error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:110:22 + --> $DIR/wrong-number-of-args.rs:116:22 | LL | type A = Box<dyn NonGeneric<usize>>; | ^^^^^^^^^^------- help: remove these generics @@ -286,13 +314,13 @@ LL | type A = Box<dyn NonGeneric<usize>>; | expected 0 generic arguments | note: trait defined here, with 0 generic parameters - --> $DIR/wrong-number-of-args.rs:98:11 + --> $DIR/wrong-number-of-args.rs:104:11 | LL | trait NonGeneric { | ^^^^^^^^^^ error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:114:22 + --> $DIR/wrong-number-of-args.rs:120:22 | LL | type B = Box<dyn GenericLifetime>; | ^^^^^^^^^^^^^^^ expected named lifetime parameter @@ -303,7 +331,7 @@ LL | type B<'a> = Box<dyn GenericLifetime<'a>>; | ^^^^ ^^^^^^^^^^^^^^^^^^^ error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:118:22 + --> $DIR/wrong-number-of-args.rs:124:22 | LL | type C = Box<dyn GenericLifetime<'static, 'static>>; | ^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -311,19 +339,19 @@ LL | type C = Box<dyn GenericLifetime<'static, 'static>>; | expected 1 lifetime argument | note: trait defined here, with 1 lifetime parameter: `'a` - --> $DIR/wrong-number-of-args.rs:102:11 + --> $DIR/wrong-number-of-args.rs:108:11 | LL | trait GenericLifetime<'a> { | ^^^^^^^^^^^^^^^ -- error[E0107]: missing generics for trait `GenericType` - --> $DIR/wrong-number-of-args.rs:122:22 + --> $DIR/wrong-number-of-args.rs:128:22 | LL | type D = Box<dyn GenericType>; | ^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:106:11 + --> $DIR/wrong-number-of-args.rs:112:11 | LL | trait GenericType<A> { | ^^^^^^^^^^^ - @@ -333,7 +361,7 @@ LL | type D = Box<dyn GenericType<A>>; | ^^^^^^^^^^^^^^ error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:126:22 + --> $DIR/wrong-number-of-args.rs:132:22 | LL | type E = Box<dyn GenericType<String, usize>>; | ^^^^^^^^^^^ ----- help: remove this generic argument @@ -341,13 +369,13 @@ LL | type E = Box<dyn GenericType<String, usize>>; | expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:106:11 + --> $DIR/wrong-number-of-args.rs:112:11 | LL | trait GenericType<A> { | ^^^^^^^^^^^ - error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:130:37 + --> $DIR/wrong-number-of-args.rs:136:37 | LL | type F = Box<dyn GenericLifetime<>>; | ^- expected named lifetime parameter @@ -358,13 +386,13 @@ LL | type F<'a> = Box<dyn GenericLifetime<'a>>; | ^^^^ ^^ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:134:22 + --> $DIR/wrong-number-of-args.rs:140:22 | LL | type G = Box<dyn GenericType<>>; | ^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:106:11 + --> $DIR/wrong-number-of-args.rs:112:11 | LL | trait GenericType<A> { | ^^^^^^^^^^^ - @@ -374,7 +402,7 @@ LL | type G = Box<dyn GenericType<A>>; | ^ error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:145:26 + --> $DIR/wrong-number-of-args.rs:151:26 | LL | type A = Box<dyn NonGenericAT<usize, AssocTy=()>>; | ^^^^^^^^^^^^------------------- help: remove these generics @@ -382,13 +410,13 @@ LL | type A = Box<dyn NonGenericAT<usize, AssocTy=()>>; | expected 0 generic arguments | note: trait defined here, with 0 generic parameters - --> $DIR/wrong-number-of-args.rs:141:15 + --> $DIR/wrong-number-of-args.rs:147:15 | LL | trait NonGenericAT { | ^^^^^^^^^^^^ error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:155:44 + --> $DIR/wrong-number-of-args.rs:161:44 | LL | type A = Box<dyn GenericLifetimeAT<AssocTy=()>>; | ^ expected named lifetime parameter @@ -399,7 +427,7 @@ LL | type A<'a> = Box<dyn GenericLifetimeAT<'a, AssocTy=()>>; | ^^^^ ^^^ error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:159:26 + --> $DIR/wrong-number-of-args.rs:165:26 | LL | type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>; | ^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -407,13 +435,13 @@ LL | type B = Box<dyn GenericLifetimeAT<'static, 'static, AssocTy=()>>; | expected 1 lifetime argument | note: trait defined here, with 1 lifetime parameter: `'a` - --> $DIR/wrong-number-of-args.rs:151:15 + --> $DIR/wrong-number-of-args.rs:157:15 | LL | trait GenericLifetimeAT<'a> { | ^^^^^^^^^^^^^^^^^ -- error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:163:44 + --> $DIR/wrong-number-of-args.rs:169:44 | LL | type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>; | ^ expected named lifetime parameter @@ -424,7 +452,7 @@ LL | type C<'a> = Box<dyn GenericLifetimeAT<'a, (), AssocTy=()>>; | ^^^^ ^^^ error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:163:26 + --> $DIR/wrong-number-of-args.rs:169:26 | LL | type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>; | ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -432,19 +460,19 @@ LL | type C = Box<dyn GenericLifetimeAT<(), AssocTy=()>>; | expected 0 generic arguments | note: trait defined here, with 0 generic parameters - --> $DIR/wrong-number-of-args.rs:151:15 + --> $DIR/wrong-number-of-args.rs:157:15 | LL | trait GenericLifetimeAT<'a> { | ^^^^^^^^^^^^^^^^^ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:175:26 + --> $DIR/wrong-number-of-args.rs:181:26 | LL | type A = Box<dyn GenericTypeAT<AssocTy=()>>; | ^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:171:15 + --> $DIR/wrong-number-of-args.rs:177:15 | LL | trait GenericTypeAT<A> { | ^^^^^^^^^^^^^ - @@ -454,7 +482,7 @@ LL | type A = Box<dyn GenericTypeAT<A, AssocTy=()>>; | ^^ error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:179:26 + --> $DIR/wrong-number-of-args.rs:185:26 | LL | type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>; | ^^^^^^^^^^^^^ -- help: remove this generic argument @@ -462,13 +490,13 @@ LL | type B = Box<dyn GenericTypeAT<(), (), AssocTy=()>>; | expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:171:15 + --> $DIR/wrong-number-of-args.rs:177:15 | LL | trait GenericTypeAT<A> { | ^^^^^^^^^^^^^ - error[E0107]: this trait takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:183:26 + --> $DIR/wrong-number-of-args.rs:189:26 | LL | type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>; | ^^^^^^^^^^^^^--------------------- help: remove these generics @@ -476,19 +504,19 @@ LL | type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>; | expected 0 lifetime arguments | note: trait defined here, with 0 lifetime parameters - --> $DIR/wrong-number-of-args.rs:171:15 + --> $DIR/wrong-number-of-args.rs:177:15 | LL | trait GenericTypeAT<A> { | ^^^^^^^^^^^^^ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:183:26 + --> $DIR/wrong-number-of-args.rs:189:26 | LL | type C = Box<dyn GenericTypeAT<'static, AssocTy=()>>; | ^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:171:15 + --> $DIR/wrong-number-of-args.rs:177:15 | LL | trait GenericTypeAT<A> { | ^^^^^^^^^^^^^ - @@ -498,7 +526,7 @@ LL | type C = Box<dyn GenericTypeAT<'static, A, AssocTy=()>>; | ^^^ error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:195:48 + --> $DIR/wrong-number-of-args.rs:201:48 | LL | type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>; | ^ expected named lifetime parameter @@ -509,13 +537,13 @@ LL | type A<'a> = Box<dyn GenericLifetimeTypeAT<'a, AssocTy=()>>; | ^^^^ ^^^ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:195:26 + --> $DIR/wrong-number-of-args.rs:201:26 | LL | type A = Box<dyn GenericLifetimeTypeAT<AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:191:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - @@ -525,13 +553,13 @@ LL | type A = Box<dyn GenericLifetimeTypeAT<A, AssocTy=()>>; | ^^ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:201:26 + --> $DIR/wrong-number-of-args.rs:207:26 | LL | type B = Box<dyn GenericLifetimeTypeAT<'static, AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:191:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - @@ -541,7 +569,7 @@ LL | type B = Box<dyn GenericLifetimeTypeAT<'static, A, AssocTy=()>>; | ^^^ error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:205:26 + --> $DIR/wrong-number-of-args.rs:211:26 | LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -549,19 +577,19 @@ LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=() | expected 1 lifetime argument | note: trait defined here, with 1 lifetime parameter: `'a` - --> $DIR/wrong-number-of-args.rs:191:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ -- error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:205:26 + --> $DIR/wrong-number-of-args.rs:211:26 | LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:191:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - @@ -571,7 +599,7 @@ LL | type C = Box<dyn GenericLifetimeTypeAT<'static, 'static, A, AssocTy | ^^^ error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:211:48 + --> $DIR/wrong-number-of-args.rs:217:48 | LL | type D = Box<dyn GenericLifetimeTypeAT<(), AssocTy=()>>; | ^ expected named lifetime parameter @@ -582,7 +610,7 @@ LL | type D<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), AssocTy=()>>; | ^^^^ ^^^ error[E0106]: missing lifetime specifier - --> $DIR/wrong-number-of-args.rs:215:48 + --> $DIR/wrong-number-of-args.rs:221:48 | LL | type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>; | ^ expected named lifetime parameter @@ -593,7 +621,7 @@ LL | type E<'a> = Box<dyn GenericLifetimeTypeAT<'a, (), (), AssocTy=()>> | ^^^^ ^^^ error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:215:26 + --> $DIR/wrong-number-of-args.rs:221:26 | LL | type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -601,13 +629,13 @@ LL | type E = Box<dyn GenericLifetimeTypeAT<(), (), AssocTy=()>>; | expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:191:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:221:26 + --> $DIR/wrong-number-of-args.rs:227:26 | LL | type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -615,13 +643,13 @@ LL | type F = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), AssocT | expected 1 lifetime argument | note: trait defined here, with 1 lifetime parameter: `'a` - --> $DIR/wrong-number-of-args.rs:191:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ -- error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:225:26 + --> $DIR/wrong-number-of-args.rs:231:26 | LL | type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -629,13 +657,13 @@ LL | type G = Box<dyn GenericLifetimeTypeAT<'static, (), (), AssocTy=()> | expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:191:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - error[E0107]: this trait takes 1 lifetime argument but 2 lifetime arguments were supplied - --> $DIR/wrong-number-of-args.rs:229:26 + --> $DIR/wrong-number-of-args.rs:235:26 | LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^ ------- help: remove this lifetime argument @@ -643,13 +671,13 @@ LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), As | expected 1 lifetime argument | note: trait defined here, with 1 lifetime parameter: `'a` - --> $DIR/wrong-number-of-args.rs:191:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ -- error[E0107]: this trait takes 1 generic argument but 2 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:229:26 + --> $DIR/wrong-number-of-args.rs:235:26 | LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -657,19 +685,19 @@ LL | type H = Box<dyn GenericLifetimeTypeAT<'static, 'static, (), (), As | expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:191:15 + --> $DIR/wrong-number-of-args.rs:197:15 | LL | trait GenericLifetimeTypeAT<'a, A> { | ^^^^^^^^^^^^^^^^^^^^^ - error[E0107]: this trait takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:241:26 + --> $DIR/wrong-number-of-args.rs:247:26 | LL | type A = Box<dyn GenericTypeTypeAT<AssocTy=()>>; | ^^^^^^^^^^^^^^^^^ expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `A`, `B` - --> $DIR/wrong-number-of-args.rs:237:15 + --> $DIR/wrong-number-of-args.rs:243:15 | LL | trait GenericTypeTypeAT<A, B> { | ^^^^^^^^^^^^^^^^^ - - @@ -679,7 +707,7 @@ LL | type A = Box<dyn GenericTypeTypeAT<A, B, AssocTy=()>>; | ^^^^^ error[E0107]: this trait takes 2 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:245:26 + --> $DIR/wrong-number-of-args.rs:251:26 | LL | type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>; | ^^^^^^^^^^^^^^^^^ -- supplied 1 generic argument @@ -687,7 +715,7 @@ LL | type B = Box<dyn GenericTypeTypeAT<(), AssocTy=()>>; | expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `A`, `B` - --> $DIR/wrong-number-of-args.rs:237:15 + --> $DIR/wrong-number-of-args.rs:243:15 | LL | trait GenericTypeTypeAT<A, B> { | ^^^^^^^^^^^^^^^^^ - - @@ -697,7 +725,7 @@ LL | type B = Box<dyn GenericTypeTypeAT<(), B, AssocTy=()>>; | ^^^ error[E0107]: this trait takes 2 generic arguments but 3 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:249:26 + --> $DIR/wrong-number-of-args.rs:255:26 | LL | type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>; | ^^^^^^^^^^^^^^^^^ -- help: remove this generic argument @@ -705,13 +733,13 @@ LL | type C = Box<dyn GenericTypeTypeAT<(), (), (), AssocTy=()>>; | expected 2 generic arguments | note: trait defined here, with 2 generic parameters: `A`, `B` - --> $DIR/wrong-number-of-args.rs:237:15 + --> $DIR/wrong-number-of-args.rs:243:15 | LL | trait GenericTypeTypeAT<A, B> { | ^^^^^^^^^^^^^^^^^ - - error[E0106]: missing lifetime specifiers - --> $DIR/wrong-number-of-args.rs:259:52 + --> $DIR/wrong-number-of-args.rs:265:52 | LL | type A = Box<dyn GenericLifetimeLifetimeAT<AssocTy=()>>; | ^ expected 2 lifetime parameters @@ -722,7 +750,7 @@ LL | type A<'a> = Box<dyn GenericLifetimeLifetimeAT<'a, 'a, AssocTy=()>> | ^^^^ ^^^^^^^ error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:263:26 + --> $DIR/wrong-number-of-args.rs:269:26 | LL | type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument @@ -730,7 +758,7 @@ LL | type B = Box<dyn GenericLifetimeLifetimeAT<'static, AssocTy=()>>; | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'a`, `'b` - --> $DIR/wrong-number-of-args.rs:255:15 + --> $DIR/wrong-number-of-args.rs:261:15 | LL | trait GenericLifetimeLifetimeAT<'a, 'b> { | ^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- @@ -740,7 +768,7 @@ LL | type B = Box<dyn GenericLifetimeLifetimeAT<'static, 'b, AssocTy=()> | ^^^^ error[E0106]: missing lifetime specifiers - --> $DIR/wrong-number-of-args.rs:273:56 + --> $DIR/wrong-number-of-args.rs:279:56 | LL | type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>; | ^ expected 2 lifetime parameters @@ -751,13 +779,13 @@ LL | type A<'a> = Box<dyn GenericLifetimeLifetimeTypeAT<'a, 'a, AssocTy= | ^^^^ ^^^^^^^ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:273:26 + --> $DIR/wrong-number-of-args.rs:279:26 | LL | type A = Box<dyn GenericLifetimeLifetimeTypeAT<AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:269:15 + --> $DIR/wrong-number-of-args.rs:275:15 | LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - @@ -767,7 +795,7 @@ LL | type A = Box<dyn GenericLifetimeLifetimeTypeAT<A, AssocTy=()>>; | ^^ error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:279:26 + --> $DIR/wrong-number-of-args.rs:285:26 | LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument @@ -775,7 +803,7 @@ LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()> | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'a`, `'b` - --> $DIR/wrong-number-of-args.rs:269:15 + --> $DIR/wrong-number-of-args.rs:275:15 | LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- @@ -785,13 +813,13 @@ LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, AssocTy | ^^^^ error[E0107]: this trait takes 1 generic argument but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:279:26 + --> $DIR/wrong-number-of-args.rs:285:26 | LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 generic argument | note: trait defined here, with 1 generic parameter: `A` - --> $DIR/wrong-number-of-args.rs:269:15 + --> $DIR/wrong-number-of-args.rs:275:15 | LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - @@ -801,7 +829,7 @@ LL | type B = Box<dyn GenericLifetimeLifetimeTypeAT<'static, A, AssocTy= | ^^^ error[E0107]: this trait takes 2 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:285:26 + --> $DIR/wrong-number-of-args.rs:291:26 | LL | type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy=()>>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ------- supplied 1 lifetime argument @@ -809,7 +837,7 @@ LL | type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, (), AssocTy | expected 2 lifetime arguments | note: trait defined here, with 2 lifetime parameters: `'a`, `'b` - --> $DIR/wrong-number-of-args.rs:269:15 + --> $DIR/wrong-number-of-args.rs:275:15 | LL | trait GenericLifetimeLifetimeTypeAT<'a, 'b, A> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- -- @@ -819,7 +847,7 @@ LL | type C = Box<dyn GenericLifetimeLifetimeTypeAT<'static, 'b, (), Ass | ^^^^ error[E0107]: missing generics for struct `HashMap` - --> $DIR/wrong-number-of-args.rs:295:18 + --> $DIR/wrong-number-of-args.rs:301:18 | LL | type A = HashMap; | ^^^^^^^ expected at least 2 generic arguments @@ -835,7 +863,7 @@ LL | type A = HashMap<K, V>; | ^^^^^^^^^^^^^ error[E0107]: this struct takes at least 2 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:299:18 + --> $DIR/wrong-number-of-args.rs:305:18 | LL | type B = HashMap<String>; | ^^^^^^^ ------ supplied 1 generic argument @@ -853,7 +881,7 @@ LL | type B = HashMap<String, V>; | ^^^ error[E0107]: this struct takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:303:18 + --> $DIR/wrong-number-of-args.rs:309:18 | LL | type C = HashMap<'static>; | ^^^^^^^--------- help: remove these generics @@ -867,7 +895,7 @@ LL | pub struct HashMap<K, V, S = RandomState> { | ^^^^^^^ error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:303:18 + --> $DIR/wrong-number-of-args.rs:309:18 | LL | type C = HashMap<'static>; | ^^^^^^^ expected at least 2 generic arguments @@ -883,7 +911,7 @@ LL | type C = HashMap<'static, K, V>; | ^^^^^^ error[E0107]: this struct takes at most 3 generic arguments but 4 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:309:18 + --> $DIR/wrong-number-of-args.rs:315:18 | LL | type D = HashMap<usize, String, char, f64>; | ^^^^^^^ --- help: remove this generic argument @@ -897,7 +925,7 @@ LL | pub struct HashMap<K, V, S = RandomState> { | ^^^^^^^ - - - error[E0107]: this struct takes at least 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:313:18 + --> $DIR/wrong-number-of-args.rs:319:18 | LL | type E = HashMap<>; | ^^^^^^^ expected at least 2 generic arguments @@ -913,7 +941,7 @@ LL | type E = HashMap<K, V>; | ^^^^ error[E0107]: missing generics for enum `Result` - --> $DIR/wrong-number-of-args.rs:319:18 + --> $DIR/wrong-number-of-args.rs:325:18 | LL | type A = Result; | ^^^^^^ expected 2 generic arguments @@ -929,7 +957,7 @@ LL | type A = Result<T, E>; | ^^^^^^^^^^^^ error[E0107]: this enum takes 2 generic arguments but 1 generic argument was supplied - --> $DIR/wrong-number-of-args.rs:323:18 + --> $DIR/wrong-number-of-args.rs:329:18 | LL | type B = Result<String>; | ^^^^^^ ------ supplied 1 generic argument @@ -947,7 +975,7 @@ LL | type B = Result<String, E>; | ^^^ error[E0107]: this enum takes 0 lifetime arguments but 1 lifetime argument was supplied - --> $DIR/wrong-number-of-args.rs:327:18 + --> $DIR/wrong-number-of-args.rs:333:18 | LL | type C = Result<'static>; | ^^^^^^--------- help: remove these generics @@ -961,7 +989,7 @@ LL | pub enum Result<T, E> { | ^^^^^^ error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:327:18 + --> $DIR/wrong-number-of-args.rs:333:18 | LL | type C = Result<'static>; | ^^^^^^ expected 2 generic arguments @@ -977,7 +1005,7 @@ LL | type C = Result<'static, T, E>; | ^^^^^^ error[E0107]: this enum takes 2 generic arguments but 3 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:333:18 + --> $DIR/wrong-number-of-args.rs:339:18 | LL | type D = Result<usize, String, char>; | ^^^^^^ ---- help: remove this generic argument @@ -991,7 +1019,7 @@ LL | pub enum Result<T, E> { | ^^^^^^ - - error[E0107]: this enum takes 2 generic arguments but 0 generic arguments were supplied - --> $DIR/wrong-number-of-args.rs:337:18 + --> $DIR/wrong-number-of-args.rs:343:18 | LL | type E = Result<>; | ^^^^^^ expected 2 generic arguments @@ -1006,7 +1034,7 @@ help: add missing generic arguments LL | type E = Result<T, E>; | ^^^^ -error: aborting due to 69 previous errors +error: aborting due to 71 previous errors Some errors have detailed explanations: E0106, E0107. For more information about an error, try `rustc --explain E0106`. diff --git a/src/test/ui/impl-trait/example-calendar.rs b/src/test/ui/impl-trait/example-calendar.rs index 238f3fa31ed..45dcb74a6e0 100644 --- a/src/test/ui/impl-trait/example-calendar.rs +++ b/src/test/ui/impl-trait/example-calendar.rs @@ -3,7 +3,6 @@ #![feature(fn_traits, step_trait, - step_trait_ext, unboxed_closures, )] @@ -157,7 +156,7 @@ impl<'a, 'b> std::ops::Add<&'b NaiveDate> for &'a NaiveDate { } } -unsafe impl std::iter::Step for NaiveDate { +impl std::iter::Step for NaiveDate { fn steps_between(_: &Self, _: &Self) -> Option<usize> { unimplemented!() } diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr index d7a9e5463b3..ff99d037d19 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.full_tait.stderr @@ -1,5 +1,5 @@ warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/error-handling.rs:6:32 + --> $DIR/error-handling.rs:5:32 | LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -8,7 +8,7 @@ LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))] = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information error: lifetime may not live long enough - --> $DIR/error-handling.rs:26:16 + --> $DIR/error-handling.rs:25:16 | LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { | -- -- lifetime `'b` defined here diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr index e2d745cdec8..4b23ba81604 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.min_tait.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/error-handling.rs:26:16 + --> $DIR/error-handling.rs:25:16 | LL | fn foo<'a, 'b, 'c>(x: &'static i32, mut y: &'a i32) -> E<'b, 'c> { | -- -- lifetime `'b` defined here diff --git a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs index b5adabb7abd..1ead78e02ed 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/error-handling.rs @@ -1,6 +1,5 @@ // compile-flags:-Zborrowck=mir -#![feature(member_constraints)] // revisions: min_tait full_tait #![feature(min_type_alias_impl_trait)] #![cfg_attr(full_tait, feature(type_alias_impl_trait))] diff --git a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs index 3911769b0c6..41b6a9eb055 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/inverse-bounds.rs @@ -3,8 +3,6 @@ // revisions: migrate mir //[mir]compile-flags: -Z borrowck=mir -#![feature(member_constraints)] - trait Trait<'a, 'b> {} impl<T> Trait<'_, '_> for T {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs index 553dea7aa6e..d0277336b25 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-elided.rs @@ -3,10 +3,8 @@ // revisions: migrate mir //[mir]compile-flags: -Z borrowck=mir -#![feature(member_constraints)] - -trait Trait<'a, 'b> { } -impl<T> Trait<'_, '_> for T { } +trait Trait<'a, 'b> {} +impl<T> Trait<'_, '_> for T {} // Test case where we have elision in the impl trait and we have to // pick the right region. @@ -26,4 +24,4 @@ fn upper_bounds3<'b>(a: &u8) -> impl Trait<'_, 'b> { (a, a) } -fn main() { } +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs index 9d345502aab..b9857b7aa2f 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original-type-alias-impl-trait.rs @@ -3,10 +3,9 @@ // revisions: migrate mir //[mir]compile-flags: -Z borrowck=mir -#![feature(member_constraints)] #![feature(min_type_alias_impl_trait)] -trait Trait<'a, 'b> { } -impl<T> Trait<'_, '_> for T { } +trait Trait<'a, 'b> {} +impl<T> Trait<'_, '_> for T {} // Here we wind up selecting `'a` and `'b` in the hidden type because // those are the types that appear in the original values. @@ -28,4 +27,4 @@ fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> Foo<'a, 'b> { (a, b) } -fn main() { } +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs index c0930ec5944..be455f53350 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-original.rs @@ -3,10 +3,8 @@ // revisions: migrate mir //[mir]compile-flags: -Z borrowck=mir -#![feature(member_constraints)] - -trait Trait<'a, 'b> { } -impl<T> Trait<'_, '_> for T { } +trait Trait<'a, 'b> {} +impl<T> Trait<'_, '_> for T {} // Here we wind up selecting `'a` and `'b` in the hidden type because // those are the types that appear in the original values. @@ -26,4 +24,4 @@ fn upper_bounds<'a, 'b>(a: &'a u8, b: &'b u8) -> impl Trait<'a, 'b> { (a, b) } -fn main() { } +fn main() {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs index ed36bda7db7..7235d89019f 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-pick-other.rs @@ -3,8 +3,6 @@ // revisions: migrate mir //[mir]compile-flags: -Z borrowck=mir -#![feature(member_constraints)] - trait Trait<'a, 'b> {} impl<T> Trait<'_, '_> for T {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr index 129af80ce4a..8cf89f164b1 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.nll.stderr @@ -1,5 +1,5 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ordinary-bounds-unrelated.rs:18:74 + --> $DIR/ordinary-bounds-unrelated.rs:16:74 | LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs index db1641b0140..3a97624647e 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.rs @@ -1,7 +1,5 @@ // edition:2018 -#![feature(member_constraints)] - trait Trait<'a, 'b> {} impl<T> Trait<'_, '_> for T {} diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr index b42ff1486f0..a6bc8fec283 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unrelated.stderr @@ -1,11 +1,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ordinary-bounds-unrelated.rs:18:74 + --> $DIR/ordinary-bounds-unrelated.rs:16:74 | LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> | ^^^^^^^^^^^^^^^^^^ | note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body - --> $DIR/ordinary-bounds-unrelated.rs:18:74 + --> $DIR/ordinary-bounds-unrelated.rs:16:74 | LL | fn upper_bounds<'a, 'b, 'c, 'd, 'e>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'d, 'e> | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr index de6d5edcae5..1bcb28120ed 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.nll.stderr @@ -1,5 +1,5 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ordinary-bounds-unsuited.rs:20:62 + --> $DIR/ordinary-bounds-unsuited.rs:18:62 | LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs index 7f9c92f15a2..d4c60a4e892 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.rs @@ -1,7 +1,5 @@ // edition:2018 -#![feature(member_constraints)] - trait Trait<'a, 'b> {} impl<T> Trait<'_, '_> for T {} @@ -18,7 +16,7 @@ struct Ordinary<'a>(&'a u8); // consider the loans for both `'a` and `'b` alive. fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> - //~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds +//~^ ERROR hidden type for `impl Trait` captures lifetime that does not appear in bounds { // We return a value: // diff --git a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr index 254643c406c..a219e747415 100644 --- a/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr +++ b/src/test/ui/impl-trait/multiple-lifetimes/ordinary-bounds-unsuited.stderr @@ -1,11 +1,11 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appear in bounds - --> $DIR/ordinary-bounds-unsuited.rs:20:62 + --> $DIR/ordinary-bounds-unsuited.rs:18:62 | LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> | ^^^^^^^^^^^^^^^^^^ | note: hidden type `Ordinary<'_>` captures lifetime smaller than the function body - --> $DIR/ordinary-bounds-unsuited.rs:20:62 + --> $DIR/ordinary-bounds-unsuited.rs:18:62 | LL | fn upper_bounds<'a, 'b>(a: Ordinary<'a>, b: Ordinary<'b>) -> impl Trait<'a, 'b> | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/impl-trait/needs_least_region_or_bound.rs b/src/test/ui/impl-trait/needs_least_region_or_bound.rs index 3c8682bb62a..c4bcfe5b281 100644 --- a/src/test/ui/impl-trait/needs_least_region_or_bound.rs +++ b/src/test/ui/impl-trait/needs_least_region_or_bound.rs @@ -1,7 +1,5 @@ // check-pass -#![feature(member_constraints)] - trait MultiRegionTrait<'a, 'b> {} impl<'a, 'b> MultiRegionTrait<'a, 'b> for (&'a u32, &'b u32) {} diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs index 2e96022318b..7beb2db3969 100644 --- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs +++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.rs @@ -10,8 +10,8 @@ fn make_unit() -> Result<(), Error> { fn main() { let fut = async { - make_unit()?; //~ ERROR type annotations needed + make_unit()?; - Ok(()) + Ok(()) //~ ERROR type annotations needed }; } diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr index 2875cef6801..8e632fbc1de 100644 --- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr +++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr @@ -8,14 +8,13 @@ LL | #![feature(impl_trait_in_bindings)] = note: see issue #63065 <https://github.com/rust-lang/rust/issues/63065> for more information error[E0282]: type annotations needed for `impl Future` - --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:13:20 + --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:15:9 | LL | let fut = async { - | --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified -LL | make_unit()?; - | ^ cannot infer type of error for `?` operator - | - = note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>` + | --- consider giving `fut` the explicit type `impl Future`, where the type parameter `E` is specified +... +LL | Ok(()) + | ^^ cannot infer type for type parameter `E` declared on the enum `Result` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/inference/cannot-infer-async.rs b/src/test/ui/inference/cannot-infer-async.rs index 05f62f3d8cb..e7fabd0ffbc 100644 --- a/src/test/ui/inference/cannot-infer-async.rs +++ b/src/test/ui/inference/cannot-infer-async.rs @@ -8,8 +8,8 @@ fn make_unit() -> Result<(), Error> { fn main() { let fut = async { - make_unit()?; //~ ERROR type annotations needed + make_unit()?; - Ok(()) + Ok(()) //~ ERROR type annotations needed }; } diff --git a/src/test/ui/inference/cannot-infer-async.stderr b/src/test/ui/inference/cannot-infer-async.stderr index 282bc13e9e7..23360483361 100644 --- a/src/test/ui/inference/cannot-infer-async.stderr +++ b/src/test/ui/inference/cannot-infer-async.stderr @@ -1,12 +1,11 @@ error[E0282]: type annotations needed - --> $DIR/cannot-infer-async.rs:11:20 + --> $DIR/cannot-infer-async.rs:13:9 | LL | let fut = async { | --- consider giving `fut` a type -LL | make_unit()?; - | ^ cannot infer type of error for `?` operator - | - = note: `?` implicitly converts the error value into a type implementing `From<std::io::Error>` +... +LL | Ok(()) + | ^^ cannot infer type for type parameter `E` declared on the enum `Result` error: aborting due to previous error diff --git a/src/test/ui/inference/cannot-infer-closure-circular.stderr b/src/test/ui/inference/cannot-infer-closure-circular.stderr index 211ae13e46d..a6ddb7ae908 100644 --- a/src/test/ui/inference/cannot-infer-closure-circular.stderr +++ b/src/test/ui/inference/cannot-infer-closure-circular.stderr @@ -2,7 +2,7 @@ error[E0282]: type annotations needed for `Result<(), E>` --> $DIR/cannot-infer-closure-circular.rs:7:14 | LL | let x = |r| { - | ^ consider giving this closure parameter the explicit type `Result<(), E>`, with the type parameters specified + | ^ consider giving this closure parameter the explicit type `Result<(), E>`, where the type parameter `E` is specified error: aborting due to previous error diff --git a/src/test/ui/inference/cannot-infer-closure.rs b/src/test/ui/inference/cannot-infer-closure.rs index 8f48483c254..6e84b6d5ad0 100644 --- a/src/test/ui/inference/cannot-infer-closure.rs +++ b/src/test/ui/inference/cannot-infer-closure.rs @@ -1,6 +1,6 @@ fn main() { let x = |a: (), b: ()| { - Err(a)?; //~ ERROR type annotations needed for the closure - Ok(b) + Err(a)?; + Ok(b) //~ ERROR type annotations needed for the closure }; } diff --git a/src/test/ui/inference/cannot-infer-closure.stderr b/src/test/ui/inference/cannot-infer-closure.stderr index 0dcce9e990b..e055d1a94ff 100644 --- a/src/test/ui/inference/cannot-infer-closure.stderr +++ b/src/test/ui/inference/cannot-infer-closure.stderr @@ -1,10 +1,9 @@ error[E0282]: type annotations needed for the closure `fn((), ()) -> Result<(), _>` - --> $DIR/cannot-infer-closure.rs:3:15 + --> $DIR/cannot-infer-closure.rs:4:9 | -LL | Err(a)?; - | ^ cannot infer type of error for `?` operator +LL | Ok(b) + | ^^ cannot infer type for type parameter `E` declared on the enum `Result` | - = note: `?` implicitly converts the error value into a type implementing `From<()>` help: give this closure an explicit return type without `_` placeholders | LL | let x = |a: (), b: ()| -> Result<(), _> { diff --git a/src/test/ui/inference/cannot-infer-partial-try-return.stderr b/src/test/ui/inference/cannot-infer-partial-try-return.stderr index 86e2126e1ae..c394f6efbda 100644 --- a/src/test/ui/inference/cannot-infer-partial-try-return.stderr +++ b/src/test/ui/inference/cannot-infer-partial-try-return.stderr @@ -2,9 +2,8 @@ error[E0282]: type annotations needed for the closure `fn() -> Result<(), Qualif --> $DIR/cannot-infer-partial-try-return.rs:19:9 | LL | infallible()?; - | ^^^^^^^^^^^^^ cannot infer type of error for `?` operator + | ^^^^^^^^^^^^^ cannot infer type | - = note: `?` implicitly converts the error value into `QualifiedError<_>` using its implementation of `From<Infallible>` help: give this closure an explicit return type without `_` placeholders | LL | let x = || -> Result<(), QualifiedError<_>> { diff --git a/src/test/ui/intrinsics/issue-28575.stderr b/src/test/ui/intrinsics/issue-28575.mir.stderr index 66369decf42..c42498390c7 100644 --- a/src/test/ui/intrinsics/issue-28575.stderr +++ b/src/test/ui/intrinsics/issue-28575.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/issue-28575.rs:8:5 + --> $DIR/issue-28575.rs:11:5 | LL | FOO() | ^^^ use of extern static diff --git a/src/test/ui/intrinsics/issue-28575.rs b/src/test/ui/intrinsics/issue-28575.rs index 141136d25b2..410f664f89d 100644 --- a/src/test/ui/intrinsics/issue-28575.rs +++ b/src/test/ui/intrinsics/issue-28575.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![feature(intrinsics)] extern "C" { diff --git a/src/test/ui/intrinsics/issue-28575.thir.stderr b/src/test/ui/intrinsics/issue-28575.thir.stderr new file mode 100644 index 00000000000..c42498390c7 --- /dev/null +++ b/src/test/ui/intrinsics/issue-28575.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/issue-28575.rs:11:5 + | +LL | FOO() + | ^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 4a91198ab9f..72c0d7913e5 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -1,5 +1,7 @@ // run-pass // ignore-wasm32-bare compiled with panic=abort by default +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck // This test checks panic emitted from `mem::{uninitialized,zeroed}`. diff --git a/src/test/ui/issues/issue-11740.rs b/src/test/ui/issues/issue-11740.rs index dc10a205f24..9faeb7770a7 100644 --- a/src/test/ui/issues/issue-11740.rs +++ b/src/test/ui/issues/issue-11740.rs @@ -1,4 +1,6 @@ // check-pass +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck struct Attr { name: String, diff --git a/src/test/ui/issues/issue-14227.stderr b/src/test/ui/issues/issue-14227.mir.stderr index f9cdbe452df..8e7a2514dd6 100644 --- a/src/test/ui/issues/issue-14227.stderr +++ b/src/test/ui/issues/issue-14227.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/issue-14227.rs:4:21 + --> $DIR/issue-14227.rs:7:21 | LL | static CRASH: u32 = symbol; | ^^^^^^ use of extern static diff --git a/src/test/ui/issues/issue-14227.rs b/src/test/ui/issues/issue-14227.rs index a1fde14600a..5f866ec9061 100644 --- a/src/test/ui/issues/issue-14227.rs +++ b/src/test/ui/issues/issue-14227.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + extern "C" { pub static symbol: u32; } diff --git a/src/test/ui/issues/issue-14227.thir.stderr b/src/test/ui/issues/issue-14227.thir.stderr new file mode 100644 index 00000000000..8e7a2514dd6 --- /dev/null +++ b/src/test/ui/issues/issue-14227.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/issue-14227.rs:7:21 + | +LL | static CRASH: u32 = symbol; + | ^^^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/issues/issue-16538.stderr b/src/test/ui/issues/issue-16538.mir.stderr index 81a91db3711..d7e8c08bb01 100644 --- a/src/test/ui/issues/issue-16538.stderr +++ b/src/test/ui/issues/issue-16538.mir.stderr @@ -1,11 +1,11 @@ error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/issue-16538.rs:11:27 + --> $DIR/issue-16538.rs:14:27 | LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: `*const usize` cannot be shared between threads safely - --> $DIR/issue-16538.rs:11:1 + --> $DIR/issue-16538.rs:14:1 | LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely @@ -14,7 +14,7 @@ LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); = note: shared static variables must have a type that implements `Sync` error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/issue-16538.rs:11:34 + --> $DIR/issue-16538.rs:14:34 | LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); | ^^^^ use of extern static diff --git a/src/test/ui/issues/issue-16538.rs b/src/test/ui/issues/issue-16538.rs index 7d6eefa5b1e..1e8ecf015c8 100644 --- a/src/test/ui/issues/issue-16538.rs +++ b/src/test/ui/issues/issue-16538.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + mod Y { pub type X = usize; extern "C" { diff --git a/src/test/ui/issues/issue-16538.thir.stderr b/src/test/ui/issues/issue-16538.thir.stderr new file mode 100644 index 00000000000..435334c3228 --- /dev/null +++ b/src/test/ui/issues/issue-16538.thir.stderr @@ -0,0 +1,27 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/issue-16538.rs:14:34 + | +LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); + | ^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants + --> $DIR/issue-16538.rs:14:27 + | +LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0277]: `*const usize` cannot be shared between threads safely + --> $DIR/issue-16538.rs:14:1 + | +LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `*const usize` + = note: shared static variables must have a type that implements `Sync` + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0015, E0133, E0277. +For more information about an error, try `rustc --explain E0015`. diff --git a/src/test/ui/issues/issue-22289.stderr b/src/test/ui/issues/issue-22289.stderr index 60027853609..f90e89efb4a 100644 --- a/src/test/ui/issues/issue-22289.stderr +++ b/src/test/ui/issues/issue-22289.stderr @@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `i32` as `&(dyn Any + 'static)` LL | 0 as &dyn std::any::Any; | ^^^^^^^^^^^^^^^^^^^^^^^ invalid cast | -help: borrow the value for the cast to be valid +help: consider borrowing the value | LL | &0 as &dyn std::any::Any; | ^ diff --git a/src/test/ui/issues/issue-22312.stderr b/src/test/ui/issues/issue-22312.stderr index 823ffc6de6d..47ee544c02a 100644 --- a/src/test/ui/issues/issue-22312.stderr +++ b/src/test/ui/issues/issue-22312.stderr @@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `Self` as `&dyn Index<usize, Output = <Self as LL | let indexer = &(*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ invalid cast | -help: borrow the value for the cast to be valid +help: consider borrowing the value | LL | let indexer = &(&*self as &dyn Index<usize, Output = <Self as Index<usize>>::Output>); | ^ diff --git a/src/test/ui/issues/issue-28324.stderr b/src/test/ui/issues/issue-28324.mir.stderr index d7dad992152..aff8bf7927d 100644 --- a/src/test/ui/issues/issue-28324.stderr +++ b/src/test/ui/issues/issue-28324.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/issue-28324.rs:5:24 + --> $DIR/issue-28324.rs:8:24 | LL | pub static BAZ: u32 = *&error_message_count; | ^^^^^^^^^^^^^^^^^^^^ use of extern static diff --git a/src/test/ui/issues/issue-28324.rs b/src/test/ui/issues/issue-28324.rs index f74726e8166..fbe83e325ed 100644 --- a/src/test/ui/issues/issue-28324.rs +++ b/src/test/ui/issues/issue-28324.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + extern "C" { static error_message_count: u32; } diff --git a/src/test/ui/issues/issue-28324.thir.stderr b/src/test/ui/issues/issue-28324.thir.stderr new file mode 100644 index 00000000000..c696c359830 --- /dev/null +++ b/src/test/ui/issues/issue-28324.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/issue-28324.rs:8:25 + | +LL | pub static BAZ: u32 = *&error_message_count; + | ^^^^^^^^^^^^^^^^^^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/issues/issue-2995.stderr b/src/test/ui/issues/issue-2995.stderr index 9f5968399a3..b08fe8c7352 100644 --- a/src/test/ui/issues/issue-2995.stderr +++ b/src/test/ui/issues/issue-2995.stderr @@ -2,7 +2,12 @@ error[E0605]: non-primitive cast: `*const isize` as `&isize` --> $DIR/issue-2995.rs:2:22 | LL | let _q: &isize = p as &isize; - | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | ^^^^^^^^^^^ invalid cast + | +help: consider borrowing the value + | +LL | let _q: &isize = &*p as &isize; + | ^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-30123.stderr b/src/test/ui/issues/issue-30123.stderr index bc6731601f0..e9d934332f1 100644 --- a/src/test/ui/issues/issue-30123.stderr +++ b/src/test/ui/issues/issue-30123.stderr @@ -3,6 +3,9 @@ error[E0599]: no function or associated item named `new_undirected` found for st | LL | let ug = Graph::<i32, i32>::new_undirected(); | ^^^^^^^^^^^^^^ function or associated item not found in `issue_30123_aux::Graph<i32, i32>` + | + = note: the function or associated item was found for + - `issue_30123_aux::Graph<N, E, Undirected>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr index cc12c153621..2d020188198 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -7,7 +7,8 @@ LL | Err(5)?; | ^ the trait `From<{integer}>` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `from` + = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, {integer}>>` for `Result<i32, ()>` + = note: required by `from_residual` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-39367.rs b/src/test/ui/issues/issue-39367.rs index 8314be3d14c..e7beb8a0392 100644 --- a/src/test/ui/issues/issue-39367.rs +++ b/src/test/ui/issues/issue-39367.rs @@ -1,4 +1,7 @@ // run-pass +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck + use std::ops::Deref; struct ArenaSet<U: Deref, V=<U as Deref>::Target>(U, &'static V) diff --git a/src/test/ui/issues/issue-41880.stderr b/src/test/ui/issues/issue-41880.stderr index 09d5594f73f..017dd831f71 100644 --- a/src/test/ui/issues/issue-41880.stderr +++ b/src/test/ui/issues/issue-41880.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `iter` found for struct `Iterate<{integer}, [closure@$DIR/issue-41880.rs:26:24: 26:31]>` in the current scope +error[E0599]: no method named `iter` found for struct `Iterate` in the current scope --> $DIR/issue-41880.rs:27:24 | LL | pub struct Iterate<T, F> { diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr index 321698e7636..9e9cbcf33ae 100644 --- a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.stderr +++ b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.mir.stderr @@ -1,5 +1,5 @@ error: unnecessary `unsafe` block - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:7:13 + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -8,13 +8,13 @@ LL | unsafe { | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:1:8 + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8 | LL | #[deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:9:38 + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38 | LL | unsafe { | ------ because it's nested under this `unsafe` block @@ -23,7 +23,7 @@ LL | |w: &mut Vec<u32>| { unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:13:34 + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34 | LL | unsafe { | ------ because it's nested under this `unsafe` block diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs index de275ff701a..ac1cfd62a05 100644 --- a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs +++ b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck + #[deny(unused_unsafe)] fn main() { let mut v = Vec::<i32>::with_capacity(24); diff --git a/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr new file mode 100644 index 00000000000..9e9cbcf33ae --- /dev/null +++ b/src/test/ui/issues/issue-45107-unnecessary-unsafe-in-closure.thir.stderr @@ -0,0 +1,35 @@ +error: unnecessary `unsafe` block + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:10:13 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +LL | let f = |v: &mut Vec<_>| { +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:4:8 + | +LL | #[deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:12:38 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | |w: &mut Vec<u32>| { unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/issue-45107-unnecessary-unsafe-in-closure.rs:16:34 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +... +LL | |x: &mut Vec<u32>| { unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: aborting due to 3 previous errors + diff --git a/src/test/ui/issues/issue-47412.stderr b/src/test/ui/issues/issue-47412.mir.stderr index aebcbf07463..96e50ba6799 100644 --- a/src/test/ui/issues/issue-47412.stderr +++ b/src/test/ui/issues/issue-47412.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: access to union field is unsafe and requires unsafe function or block - --> $DIR/issue-47412.rs:11:11 + --> $DIR/issue-47412.rs:14:11 | LL | match u.void {} | ^^^^^^ access to union field @@ -7,7 +7,7 @@ LL | match u.void {} = note: the field may not be properly initialized: using uninitialized data will cause undefined behavior error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/issue-47412.rs:17:11 + --> $DIR/issue-47412.rs:21:11 | LL | match *ptr {} | ^^^^ dereference of raw pointer diff --git a/src/test/ui/issues/issue-47412.rs b/src/test/ui/issues/issue-47412.rs index 2d1ea72280b..d395285eee0 100644 --- a/src/test/ui/issues/issue-47412.rs +++ b/src/test/ui/issues/issue-47412.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #[derive(Copy, Clone)] enum Void {} @@ -9,7 +12,8 @@ fn union_field() { union Union { unit: (), void: Void } let u = Union { unit: () }; match u.void {} - //~^ ERROR access to union field is unsafe + //[mir]~^ ERROR access to union field is unsafe + // FIXME(thir-unsafeck): AccessToUnionField unimplemented } fn raw_ptr_deref() { diff --git a/src/test/ui/issues/issue-47412.thir.stderr b/src/test/ui/issues/issue-47412.thir.stderr new file mode 100644 index 00000000000..66a0cfcd710 --- /dev/null +++ b/src/test/ui/issues/issue-47412.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/issue-47412.rs:21:11 + | +LL | match *ptr {} + | ^^^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/lang-item-missing-generator.rs b/src/test/ui/lang-items/lang-item-missing-generator.rs index 0c329542928..0c329542928 100644 --- a/src/test/ui/lang-item-missing-generator.rs +++ b/src/test/ui/lang-items/lang-item-missing-generator.rs diff --git a/src/test/ui/lang-item-missing-generator.stderr b/src/test/ui/lang-items/lang-item-missing-generator.stderr index fa13bf0b127..fa13bf0b127 100644 --- a/src/test/ui/lang-item-missing-generator.stderr +++ b/src/test/ui/lang-items/lang-item-missing-generator.stderr diff --git a/src/test/ui/lang-item-missing.rs b/src/test/ui/lang-items/lang-item-missing.rs index 4e26343242e..4e26343242e 100644 --- a/src/test/ui/lang-item-missing.rs +++ b/src/test/ui/lang-items/lang-item-missing.rs diff --git a/src/test/ui/lang-item-missing.stderr b/src/test/ui/lang-items/lang-item-missing.stderr index f7516c7d377..f7516c7d377 100644 --- a/src/test/ui/lang-item-missing.stderr +++ b/src/test/ui/lang-items/lang-item-missing.stderr diff --git a/src/test/ui/lang-items/wrong-number-generic-args-add.rs b/src/test/ui/lang-items/wrong-number-generic-args-add.rs new file mode 100644 index 00000000000..9f4f2464a1e --- /dev/null +++ b/src/test/ui/lang-items/wrong-number-generic-args-add.rs @@ -0,0 +1,20 @@ +// Checks whether declaring a lang item with the wrong number +// of generic arguments crashes the compiler (issue #83893). + +#![feature(lang_items,no_core)] +#![no_core] +#![crate_type="lib"] + +#[lang = "sized"] +trait MySized {} + +#[lang = "add"] +trait MyAdd<'a, T> {} +//~^^ ERROR: `add` language item must be applied to a trait with 1 generic argument [E0718] + +fn ice() { + let r = 5; + let a = 6; + r + a + //~^ ERROR: cannot add `{integer}` to `{integer}` [E0369] +} diff --git a/src/test/ui/lang-items/wrong-number-generic-args-add.stderr b/src/test/ui/lang-items/wrong-number-generic-args-add.stderr new file mode 100644 index 00000000000..6f89441fd28 --- /dev/null +++ b/src/test/ui/lang-items/wrong-number-generic-args-add.stderr @@ -0,0 +1,20 @@ +error[E0718]: `add` language item must be applied to a trait with 1 generic argument + --> $DIR/wrong-number-generic-args-add.rs:11:1 + | +LL | #[lang = "add"] + | ^^^^^^^^^^^^^^^ +LL | trait MyAdd<'a, T> {} + | ------- this trait has 2 generic arguments, not 1 + +error[E0369]: cannot add `{integer}` to `{integer}` + --> $DIR/wrong-number-generic-args-add.rs:18:7 + | +LL | r + a + | - ^ - {integer} + | | + | {integer} + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0369, E0718. +For more information about an error, try `rustc --explain E0369`. diff --git a/src/test/ui/lang-items/wrong-number-generic-args-index.rs b/src/test/ui/lang-items/wrong-number-generic-args-index.rs new file mode 100644 index 00000000000..1d90e63dc54 --- /dev/null +++ b/src/test/ui/lang-items/wrong-number-generic-args-index.rs @@ -0,0 +1,19 @@ +// Checks whether declaring a lang item with the wrong number +// of generic arguments crashes the compiler (issue #83893). + +#![feature(lang_items,no_core)] +#![no_core] +#![crate_type="lib"] + +#[lang = "sized"] +trait MySized {} + +#[lang = "index"] +trait MyIndex<'a, T> {} +//~^^ ERROR: `index` language item must be applied to a trait with 1 generic argument [E0718] + +fn ice() { + let arr = [0; 5]; + let _ = arr[2]; + //~^ ERROR: cannot index into a value of type `[{integer}; 5]` [E0608] +} diff --git a/src/test/ui/lang-items/wrong-number-generic-args-index.stderr b/src/test/ui/lang-items/wrong-number-generic-args-index.stderr new file mode 100644 index 00000000000..bc3f19ff276 --- /dev/null +++ b/src/test/ui/lang-items/wrong-number-generic-args-index.stderr @@ -0,0 +1,18 @@ +error[E0718]: `index` language item must be applied to a trait with 1 generic argument + --> $DIR/wrong-number-generic-args-index.rs:11:1 + | +LL | #[lang = "index"] + | ^^^^^^^^^^^^^^^^^ +LL | trait MyIndex<'a, T> {} + | ------- this trait has 2 generic arguments, not 1 + +error[E0608]: cannot index into a value of type `[{integer}; 5]` + --> $DIR/wrong-number-generic-args-index.rs:17:13 + | +LL | let _ = arr[2]; + | ^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0608, E0718. +For more information about an error, try `rustc --explain E0608`. diff --git a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs new file mode 100644 index 00000000000..d4a5056ddf3 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.rs @@ -0,0 +1,11 @@ +// compile-flags: --force-warns elided_lifetimes_in_paths +// check-pass + +struct Foo<'a> { + x: &'a u32, +} + +fn foo(x: &Foo) {} +//~^ WARN hidden lifetime parameters in types are deprecated + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr new file mode 100644 index 00000000000..0e0e934c765 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-allowed-by-default-lint.stderr @@ -0,0 +1,10 @@ +warning: hidden lifetime parameters in types are deprecated + --> $DIR/force-allowed-by-default-lint.rs:8:12 + | +LL | fn foo(x: &Foo) {} + | ^^^- help: indicate the anonymous lifetime: `<'_>` + | + = note: warning forced by `force-warns` commandline option + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs new file mode 100644 index 00000000000..afd2d6ec322 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.rs @@ -0,0 +1,9 @@ +// compile-flags: --force-warns const_err +// check-pass + +#![allow(const_err)] +const C: i32 = 1 / 0; +//~^ WARN any use of this value will cause an error +//~| WARN this was previously accepted by the compiler + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr new file mode 100644 index 00000000000..bad12f94b18 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-allowed-deny-by-default-lint.stderr @@ -0,0 +1,14 @@ +warning: any use of this value will cause an error + --> $DIR/force-allowed-deny-by-default-lint.rs:5:16 + | +LL | const C: i32 = 1 / 0; + | ---------------^^^^^- + | | + | attempt to divide `1_i32` by zero + | + = note: warning forced by `force-warns` commandline option + = 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> + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/force-warn/force-allowed-warning.rs b/src/test/ui/lint/force-warn/force-allowed-warning.rs new file mode 100644 index 00000000000..5c83c525e38 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-allowed-warning.rs @@ -0,0 +1,9 @@ +// compile-flags: --force-warns dead_code +// check-pass + +#![allow(dead_code)] + +fn dead_function() {} +//~^ WARN function is never used + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-allowed-warning.stderr b/src/test/ui/lint/force-warn/force-allowed-warning.stderr new file mode 100644 index 00000000000..145798a32a9 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-allowed-warning.stderr @@ -0,0 +1,10 @@ +warning: function is never used: `dead_function` + --> $DIR/force-allowed-warning.rs:6:4 + | +LL | fn dead_function() {} + | ^^^^^^^^^^^^^ + | + = note: warning forced by `force-warns` commandline option + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs b/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs new file mode 100644 index 00000000000..4f267f085d5 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-deny-by-default-lint.rs @@ -0,0 +1,8 @@ +// compile-flags: --force-warns const_err +// check-pass + +const C: i32 = 1 / 0; +//~^ WARN any use of this value will cause an error +//~| WARN this was previously accepted by the compiler + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr b/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr new file mode 100644 index 00000000000..4b004cf367d --- /dev/null +++ b/src/test/ui/lint/force-warn/force-deny-by-default-lint.stderr @@ -0,0 +1,14 @@ +warning: any use of this value will cause an error + --> $DIR/force-deny-by-default-lint.rs:4:16 + | +LL | const C: i32 = 1 / 0; + | ---------------^^^^^- + | | + | attempt to divide `1_i32` by zero + | + = note: warning forced by `force-warns` commandline option + = 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> + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs new file mode 100644 index 00000000000..5501faa437a --- /dev/null +++ b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.rs @@ -0,0 +1,9 @@ +// compile-flags: --force-warns dead_code +// check-pass + +#![allow(warnings)] + +fn dead_function() {} +//~^ WARN function is never used + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr new file mode 100644 index 00000000000..577dbe1fea8 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-lint-allow-all-warnings.stderr @@ -0,0 +1,10 @@ +warning: function is never used: `dead_function` + --> $DIR/force-lint-allow-all-warnings.rs:6:4 + | +LL | fn dead_function() {} + | ^^^^^^^^^^^^^ + | + = note: warning forced by `force-warns` commandline option + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs new file mode 100644 index 00000000000..9009971f0cf --- /dev/null +++ b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.rs @@ -0,0 +1,9 @@ +// compile-flags: --force-warns nonstandard_style +// check-pass + +#![allow(warnings)] + +pub fn FUNCTION() {} +//~^ WARN function `FUNCTION` should have a snake case name + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr new file mode 100644 index 00000000000..8665fa2610a --- /dev/null +++ b/src/test/ui/lint/force-warn/force-lint-group-allow-all-warnings.stderr @@ -0,0 +1,10 @@ +warning: function `FUNCTION` should have a snake case name + --> $DIR/force-lint-group-allow-all-warnings.rs:6:8 + | +LL | pub fn FUNCTION() {} + | ^^^^^^^^ help: convert the identifier to snake case: `function` + | + = note: warning forced by `force-warns` commandline option + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs new file mode 100644 index 00000000000..b68b979ca11 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.rs @@ -0,0 +1,12 @@ +// compile-flags: --force-warns bare_trait_objects +// check-pass + +#![allow(rust_2018_idioms)] + +pub trait SomeTrait {} + +pub fn function(_x: Box<SomeTrait>) {} +//~^ WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this was previously accepted by the compiler + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr new file mode 100644 index 00000000000..40750ffea8c --- /dev/null +++ b/src/test/ui/lint/force-warn/force-lint-in-allowed-group.stderr @@ -0,0 +1,12 @@ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/force-lint-in-allowed-group.rs:8:25 + | +LL | pub fn function(_x: Box<SomeTrait>) {} + | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait` + | + = note: warning forced by `force-warns` commandline option + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165> + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs new file mode 100644 index 00000000000..357a79b383d --- /dev/null +++ b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.rs @@ -0,0 +1,12 @@ +// compile-flags: --force-warns rust_2018_idioms +// check-pass + +#![allow(bare_trait_objects)] + +pub trait SomeTrait {} + +pub fn function(_x: Box<SomeTrait>) {} +//~^ WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this was previously accepted by the compiler + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr new file mode 100644 index 00000000000..88ae846caa0 --- /dev/null +++ b/src/test/ui/lint/force-warn/force-warn-group-allow-warning.stderr @@ -0,0 +1,12 @@ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/force-warn-group-allow-warning.rs:8:25 + | +LL | pub fn function(_x: Box<SomeTrait>) {} + | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait` + | + = note: warning forced by `force-warns` commandline option + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165> + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/force-warn/force-warn-group.rs b/src/test/ui/lint/force-warn/force-warn-group.rs new file mode 100644 index 00000000000..a4615df42de --- /dev/null +++ b/src/test/ui/lint/force-warn/force-warn-group.rs @@ -0,0 +1,12 @@ +// compile-flags: --force-warns rust_2018_idioms +// check-pass + +#![allow(rust_2018_idioms)] + +pub trait SomeTrait {} + +pub fn function(_x: Box<SomeTrait>) {} +//~^ WARN trait objects without an explicit `dyn` are deprecated +//~| WARN this was previously accepted by the compiler + +fn main() {} diff --git a/src/test/ui/lint/force-warn/force-warn-group.stderr b/src/test/ui/lint/force-warn/force-warn-group.stderr new file mode 100644 index 00000000000..f808727991e --- /dev/null +++ b/src/test/ui/lint/force-warn/force-warn-group.stderr @@ -0,0 +1,12 @@ +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/force-warn-group.rs:8:25 + | +LL | pub fn function(_x: Box<SomeTrait>) {} + | ^^^^^^^^^ help: use `dyn`: `dyn SomeTrait` + | + = note: warning forced by `force-warns` commandline option + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2021 edition! + = note: for more information, see issue #80165 <https://github.com/rust-lang/rust/issues/80165> + +warning: 1 warning emitted + diff --git a/src/test/ui/lint/lint-stability-deprecated.stderr b/src/test/ui/lint/lint-stability-deprecated.stderr index 94fc1a7b46d..4b082fcd359 100644 --- a/src/test/ui/lint/lint-stability-deprecated.stderr +++ b/src/test/ui/lint/lint-stability-deprecated.stderr @@ -11,16 +11,16 @@ LL | #![warn(deprecated)] | ^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:29:9 + --> $DIR/lint-stability-deprecated.rs:29:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:31:9 + --> $DIR/lint-stability-deprecated.rs:31:25 | LL | <Foo as Trait>::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated function `lint_stability::deprecated_text`: text --> $DIR/lint-stability-deprecated.rs:33:9 @@ -29,16 +29,16 @@ LL | deprecated_text(); | ^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:38:9 + --> $DIR/lint-stability-deprecated.rs:38:16 | LL | ... Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:40:9 + --> $DIR/lint-stability-deprecated.rs:40:25 | LL | ... <Foo as Trait>::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated function `lint_stability::deprecated_unstable`: text --> $DIR/lint-stability-deprecated.rs:42:9 @@ -47,16 +47,16 @@ LL | deprecated_unstable(); | ^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text - --> $DIR/lint-stability-deprecated.rs:47:9 + --> $DIR/lint-stability-deprecated.rs:47:16 | LL | ... Trait::trait_deprecated_unstable(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text - --> $DIR/lint-stability-deprecated.rs:49:9 + --> $DIR/lint-stability-deprecated.rs:49:25 | LL | ... <Foo as Trait>::trait_deprecated_unstable(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated function `lint_stability::deprecated_unstable_text`: text --> $DIR/lint-stability-deprecated.rs:51:9 @@ -65,16 +65,16 @@ LL | deprecated_unstable_text(); | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text - --> $DIR/lint-stability-deprecated.rs:56:9 + --> $DIR/lint-stability-deprecated.rs:56:16 | LL | ... Trait::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text - --> $DIR/lint-stability-deprecated.rs:58:9 + --> $DIR/lint-stability-deprecated.rs:58:25 | LL | ... <Foo as Trait>::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated struct `lint_stability::DeprecatedStruct`: text --> $DIR/lint-stability-deprecated.rs:108:17 @@ -101,16 +101,16 @@ LL | let _ = DeprecatedUnstableUnitStruct; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated variant `lint_stability::Enum::DeprecatedVariant`: text - --> $DIR/lint-stability-deprecated.rs:123:17 + --> $DIR/lint-stability-deprecated.rs:123:23 | LL | let _ = Enum::DeprecatedVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ warning: use of deprecated variant `lint_stability::Enum::DeprecatedUnstableVariant`: text - --> $DIR/lint-stability-deprecated.rs:124:17 + --> $DIR/lint-stability-deprecated.rs:124:23 | LL | let _ = Enum::DeprecatedUnstableVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated struct `lint_stability::DeprecatedTupleStruct`: text --> $DIR/lint-stability-deprecated.rs:128:17 @@ -143,52 +143,52 @@ LL | macro_test_arg!(macro_test_arg!(deprecated_text())); | ^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:145:9 + --> $DIR/lint-stability-deprecated.rs:145:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:147:9 + --> $DIR/lint-stability-deprecated.rs:147:25 | LL | <Foo as Trait>::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:149:9 + --> $DIR/lint-stability-deprecated.rs:149:16 | LL | ... Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:151:9 + --> $DIR/lint-stability-deprecated.rs:151:25 | LL | ... <Foo as Trait>::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text - --> $DIR/lint-stability-deprecated.rs:153:9 + --> $DIR/lint-stability-deprecated.rs:153:16 | LL | ... Trait::trait_deprecated_unstable(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable`: text - --> $DIR/lint-stability-deprecated.rs:155:9 + --> $DIR/lint-stability-deprecated.rs:155:25 | LL | ... <Foo as Trait>::trait_deprecated_unstable(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text - --> $DIR/lint-stability-deprecated.rs:157:9 + --> $DIR/lint-stability-deprecated.rs:157:16 | LL | ... Trait::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `lint_stability::Trait::trait_deprecated_unstable_text`: text - --> $DIR/lint-stability-deprecated.rs:159:9 + --> $DIR/lint-stability-deprecated.rs:159:25 | LL | ... <Foo as Trait>::trait_deprecated_unstable_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated trait `lint_stability::DeprecatedTrait`: text --> $DIR/lint-stability-deprecated.rs:187:10 @@ -203,10 +203,10 @@ LL | trait LocalTrait2 : DeprecatedTrait { } | ^^^^^^^^^^^^^^^ warning: use of deprecated function `inheritance::inherited_stability::unstable_mod::deprecated`: text - --> $DIR/lint-stability-deprecated.rs:208:9 + --> $DIR/lint-stability-deprecated.rs:208:23 | LL | unstable_mod::deprecated(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^ warning: use of deprecated function `this_crate::deprecated`: text --> $DIR/lint-stability-deprecated.rs:330:9 @@ -215,16 +215,16 @@ LL | deprecated(); | ^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:335:9 + --> $DIR/lint-stability-deprecated.rs:335:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:337:9 + --> $DIR/lint-stability-deprecated.rs:337:25 | LL | <Foo as Trait>::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated function `this_crate::deprecated_text`: text --> $DIR/lint-stability-deprecated.rs:339:9 @@ -233,16 +233,16 @@ LL | deprecated_text(); | ^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:344:9 + --> $DIR/lint-stability-deprecated.rs:344:16 | LL | Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:346:9 + --> $DIR/lint-stability-deprecated.rs:346:25 | LL | ... <Foo as Trait>::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated struct `this_crate::DeprecatedStruct`: text --> $DIR/lint-stability-deprecated.rs:384:17 @@ -257,10 +257,10 @@ LL | let _ = DeprecatedUnitStruct; | ^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated unit variant `this_crate::Enum::DeprecatedVariant`: text - --> $DIR/lint-stability-deprecated.rs:395:17 + --> $DIR/lint-stability-deprecated.rs:395:23 | LL | let _ = Enum::DeprecatedVariant; - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^ warning: use of deprecated tuple struct `this_crate::DeprecatedTupleStruct`: text --> $DIR/lint-stability-deprecated.rs:399:17 @@ -269,28 +269,28 @@ LL | let _ = DeprecatedTupleStruct (1); | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:406:9 + --> $DIR/lint-stability-deprecated.rs:406:16 | LL | Trait::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated`: text - --> $DIR/lint-stability-deprecated.rs:408:9 + --> $DIR/lint-stability-deprecated.rs:408:25 | LL | <Foo as Trait>::trait_deprecated(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:410:9 + --> $DIR/lint-stability-deprecated.rs:410:16 | LL | Trait::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated associated function `this_crate::Trait::trait_deprecated_text`: text - --> $DIR/lint-stability-deprecated.rs:412:9 + --> $DIR/lint-stability-deprecated.rs:412:25 | LL | ... <Foo as Trait>::trait_deprecated_text(&foo); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ warning: use of deprecated function `this_crate::test_fn_body::fn_in_body`: text --> $DIR/lint-stability-deprecated.rs:439:9 diff --git a/src/test/ui/lto-duplicate-symbols.stderr b/src/test/ui/lto-duplicate-symbols.stderr index 713b79bae32..891cda8016c 100644 --- a/src/test/ui/lto-duplicate-symbols.stderr +++ b/src/test/ui/lto-duplicate-symbols.stderr @@ -1,6 +1,6 @@ warning: Linking globals named 'foo': symbol multiply defined! -error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.3a1fbbbh-cgu.0.rcgu.o": +error: failed to load bc of "lto-duplicate-symbols2.lto_duplicate_symbols2.288b404e693a75b4-cgu.0.rcgu.o": error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/lto-still-runs-thread-dtors.rs b/src/test/ui/lto-still-runs-thread-dtors.rs index 635ad783b31..1c7368b36e1 100644 --- a/src/test/ui/lto-still-runs-thread-dtors.rs +++ b/src/test/ui/lto-still-runs-thread-dtors.rs @@ -2,6 +2,8 @@ // compile-flags: -C lto // no-prefer-dynamic // ignore-emscripten no threads support +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck use std::thread; diff --git a/src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs b/src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs new file mode 100644 index 00000000000..26d4c96d524 --- /dev/null +++ b/src/test/ui/macros/auxiliary/foreign-crate-macro-pat.rs @@ -0,0 +1,11 @@ +// edition:2018 + +#[macro_export] +macro_rules! custom_matches { + ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => { + match $expression { + $( $pattern )|+ $( if $guard )? => true, + _ => false + } + } +} diff --git a/src/test/ui/macros/cross-crate-pat-span.rs b/src/test/ui/macros/cross-crate-pat-span.rs new file mode 100644 index 00000000000..ed67142ce3d --- /dev/null +++ b/src/test/ui/macros/cross-crate-pat-span.rs @@ -0,0 +1,12 @@ +// edition:2021 +// check-pass +// aux-build: foreign-crate-macro-pat.rs +// +// Tests that the edition of the foreign crate is used +// when determining the behavior of the `:pat` matcher. + +extern crate foreign_crate_macro_pat; + +fn main() { + let _b = foreign_crate_macro_pat::custom_matches!(b'3', b'0' ..= b'9'); +} diff --git a/src/test/ui/macros/issue-84429-matches-edition.rs b/src/test/ui/macros/issue-84429-matches-edition.rs new file mode 100644 index 00000000000..53f134c265f --- /dev/null +++ b/src/test/ui/macros/issue-84429-matches-edition.rs @@ -0,0 +1,9 @@ +// edition:2021 +// check-pass +// +// Regression test for issue #84429 +// Tests that we can properly invoke `matches!` from a 2021-edition crate. + +fn main() { + let _b = matches!(b'3', b'0' ..= b'9'); +} diff --git a/src/test/ui/matches2021.rs b/src/test/ui/matches2021.rs new file mode 100644 index 00000000000..1090b1578ba --- /dev/null +++ b/src/test/ui/matches2021.rs @@ -0,0 +1,12 @@ +// run-pass +// edition:2021 +// compile-flags: -Zunstable-options + +// regression test for https://github.com/rust-lang/rust/pull/85678 + +#![feature(assert_matches)] + +fn main() { + assert!(matches!((), ())); + assert_matches!((), ()); +} diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.rs b/src/test/ui/methods/method-not-found-generic-arg-elision.rs new file mode 100644 index 00000000000..3df928b5d80 --- /dev/null +++ b/src/test/ui/methods/method-not-found-generic-arg-elision.rs @@ -0,0 +1,106 @@ +// Test for issue 81576 +// Remove generic arguments if no method is found for all possible generic argument + +use std::marker::PhantomData; + +struct Wrapper2<'a, T, const C: usize> { + x: &'a T, +} + +impl<'a, const C: usize> Wrapper2<'a, i8, C> { + fn method(&self) {} +} + +impl<'a, const C: usize> Wrapper2<'a, i16, C> { + fn method(&self) {} +} + +impl<'a, const C: usize> Wrapper2<'a, i32, C> { + fn method(&self) {} +} +struct Wrapper<T>(T); + +impl Wrapper<i8> { + fn method(&self) {} +} + +impl Wrapper<i16> { + fn method(&self) {} +} + +impl Wrapper<i32> { + fn method(&self) {} +} + +impl Wrapper<i64> { + fn method(&self) {} +} + +impl Wrapper<u8> { + fn method(&self) {} +} + +impl Wrapper<u16> { + fn method(&self) {} +} + +struct Point<T> { + x: T, + y: T, +} + +impl Point<f64> { + fn distance(&self) -> f64 { + self.x.hypot(self.y) + } +} + +struct Other; + +impl Other { + fn other(&self) {} +} + +struct Struct<T>{ + _phatom: PhantomData<T> +} + +impl<T> Default for Struct<T> { + fn default() -> Self { + Self{ _phatom: PhantomData } + } +} + +impl<T: Clone + Copy + PartialEq + Eq + PartialOrd + Ord> Struct<T> { + fn method(&self) {} +} + +fn main() { + let point_f64 = Point{ x: 1_f64, y: 1_f64}; + let d = point_f64.distance(); + let point_i32 = Point{ x: 1_i32, y: 1_i32}; + let d = point_i32.distance(); + //~^ ERROR no method named `distance` found for struct `Point<i32> + let d = point_i32.other(); + //~^ ERROR no method named `other` found for struct `Point + let v = vec![1_i32, 2, 3]; + v.iter().map(|x| x * x).extend(std::iter::once(100)); + //~^ ERROR no method named `extend` found for struct `Map + let wrapper = Wrapper(true); + wrapper.method(); + //~^ ERROR no method named `method` found for struct `Wrapper<bool> + wrapper.other(); + //~^ ERROR no method named `other` found for struct `Wrapper + let boolean = true; + let wrapper = Wrapper2::<'_, _, 3> {x: &boolean}; + wrapper.method(); + //~^ ERROR no method named `method` found for struct `Wrapper2<'_, bool, 3_usize> + wrapper.other(); + //~^ ERROR no method named `other` found for struct `Wrapper2 + let a = vec![1, 2, 3]; + a.not_found(); + //~^ ERROR no method named `not_found` found for struct `Vec + let s = Struct::<f64>::default(); + s.method(); + //~^ ERROR the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied +} diff --git a/src/test/ui/methods/method-not-found-generic-arg-elision.stderr b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr new file mode 100644 index 00000000000..1671e5e5e64 --- /dev/null +++ b/src/test/ui/methods/method-not-found-generic-arg-elision.stderr @@ -0,0 +1,97 @@ +error[E0599]: no method named `distance` found for struct `Point<i32>` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:82:23 + | +LL | struct Point<T> { + | --------------- method `distance` not found for this +... +LL | let d = point_i32.distance(); + | ^^^^^^^^ method not found in `Point<i32>` + | + = note: the method was found for + - `Point<f64>` + +error[E0599]: no method named `other` found for struct `Point` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:84:23 + | +LL | struct Point<T> { + | --------------- method `other` not found for this +... +LL | let d = point_i32.other(); + | ^^^^^ method not found in `Point<i32>` + +error[E0599]: no method named `extend` found for struct `Map` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:87:29 + | +LL | v.iter().map(|x| x * x).extend(std::iter::once(100)); + | ^^^^^^ method not found in `Map<std::slice::Iter<'_, i32>, [closure@$DIR/method-not-found-generic-arg-elision.rs:87:18: 87:27]>` + +error[E0599]: no method named `method` found for struct `Wrapper<bool>` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:90:13 + | +LL | struct Wrapper<T>(T); + | --------------------- method `method` not found for this +... +LL | wrapper.method(); + | ^^^^^^ method not found in `Wrapper<bool>` + | + = note: the method was found for + - `Wrapper<i8>` + - `Wrapper<i16>` + - `Wrapper<i32>` + - `Wrapper<i64>` + and 2 more types + +error[E0599]: no method named `other` found for struct `Wrapper` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:92:13 + | +LL | struct Wrapper<T>(T); + | --------------------- method `other` not found for this +... +LL | wrapper.other(); + | ^^^^^ method not found in `Wrapper<bool>` + +error[E0599]: no method named `method` found for struct `Wrapper2<'_, bool, 3_usize>` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:96:13 + | +LL | struct Wrapper2<'a, T, const C: usize> { + | -------------------------------------- method `method` not found for this +... +LL | wrapper.method(); + | ^^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>` + | + = note: the method was found for + - `Wrapper2<'a, i8, C>` + - `Wrapper2<'a, i16, C>` + - `Wrapper2<'a, i32, C>` + +error[E0599]: no method named `other` found for struct `Wrapper2` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:98:13 + | +LL | struct Wrapper2<'a, T, const C: usize> { + | -------------------------------------- method `other` not found for this +... +LL | wrapper.other(); + | ^^^^^ method not found in `Wrapper2<'_, bool, 3_usize>` + +error[E0599]: no method named `not_found` found for struct `Vec<{integer}>` in the current scope + --> $DIR/method-not-found-generic-arg-elision.rs:101:7 + | +LL | a.not_found(); + | ^^^^^^^^^ method not found in `Vec<{integer}>` + +error[E0599]: the method `method` exists for struct `Struct<f64>`, but its trait bounds were not satisfied + --> $DIR/method-not-found-generic-arg-elision.rs:104:7 + | +LL | struct Struct<T>{ + | ---------------- method `method` not found for this +... +LL | s.method(); + | ^^^^^^ method cannot be called on `Struct<f64>` due to unsatisfied trait bounds + | + = note: the following trait bounds were not satisfied: + `f64: Eq` + `f64: Ord` + +error: aborting due to 9 previous errors + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/mir/issue-80742.stderr b/src/test/ui/mir/issue-80742.stderr index 8400aab308e..961234cf7e8 100644 --- a/src/test/ui/mir/issue-80742.stderr +++ b/src/test/ui/mir/issue-80742.stderr @@ -1,4 +1,4 @@ -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | LL | intrinsics::size_of::<T>() @@ -35,7 +35,7 @@ LL | pub trait Debug { = note: the following trait bounds were not satisfied: `dyn Debug: Sized` -error[E0080]: evaluation of constant value failed +error[E0080]: evaluation of `Inline::<dyn std::fmt::Debug>::{constant#0}` failed --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | LL | intrinsics::size_of::<T>() diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 388c978d038..6a97d1ee3b8 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -24,7 +24,12 @@ error[E0605]: non-primitive cast: `*const u8` as `&u8` --> $DIR/cast-rfc0401.rs:29:13 | LL | let _ = v as &u8; - | ^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object + | ^^^^^^^^ invalid cast + | +help: consider borrowing the value + | +LL | let _ = &*v as &u8; + | ^^ error[E0605]: non-primitive cast: `*const u8` as `E` --> $DIR/cast-rfc0401.rs:30:13 diff --git a/src/test/ui/no-stdio.rs b/src/test/ui/no-stdio.rs index 68e6fa838b4..24985386a97 100644 --- a/src/test/ui/no-stdio.rs +++ b/src/test/ui/no-stdio.rs @@ -2,6 +2,8 @@ // ignore-android // ignore-emscripten no processes // ignore-sgx no processes +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck #![feature(rustc_private)] diff --git a/src/test/ui/option-to-result.stderr b/src/test/ui/option-to-result.stderr deleted file mode 100644 index 551b9f4650a..00000000000 --- a/src/test/ui/option-to-result.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0277]: `?` couldn't convert the error to `()` - --> $DIR/option-to-result.rs:5:6 - | -LL | fn test_result() -> Result<(),()> { - | ------------- expected `()` because of this -LL | let a:Option<()> = Some(()); -LL | a?; - | ^ the trait `From<NoneError>` is not implemented for `()` - | - = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `from` -help: consider converting the `Option<T>` into a `Result<T, _>` using `Option::ok_or` or `Option::ok_or_else` - | -LL | a.ok_or_else(|| /* error value */)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: `?` couldn't convert the error to `NoneError` - --> $DIR/option-to-result.rs:11:6 - | -LL | fn test_option() -> Option<i32>{ - | ----------- expected `NoneError` because of this -LL | let a:Result<i32, i32> = Ok(5); -LL | a?; - | ^ the trait `From<i32>` is not implemented for `NoneError` - | - = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `from` -help: consider converting the `Result<T, _>` into an `Option<T>` using `Result::ok` - | -LL | a.ok()?; - | ^^^^^ - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/parser/fn-field-parse-error-ice.rs b/src/test/ui/parser/fn-field-parse-error-ice.rs new file mode 100644 index 00000000000..4ea55062fc4 --- /dev/null +++ b/src/test/ui/parser/fn-field-parse-error-ice.rs @@ -0,0 +1,10 @@ +// Regression test for #85794 + +struct Baz { + inner : dyn fn () + //~^ ERROR expected `,`, or `}`, found keyword `fn` + //~| ERROR functions are not allowed in struct definitions + //~| ERROR cannot find type `dyn` in this scope +} + +fn main() {} diff --git a/src/test/ui/parser/fn-field-parse-error-ice.stderr b/src/test/ui/parser/fn-field-parse-error-ice.stderr new file mode 100644 index 00000000000..d582f61cc97 --- /dev/null +++ b/src/test/ui/parser/fn-field-parse-error-ice.stderr @@ -0,0 +1,24 @@ +error: expected `,`, or `}`, found keyword `fn` + --> $DIR/fn-field-parse-error-ice.rs:4:16 + | +LL | inner : dyn fn () + | ^ help: try adding a comma: `,` + +error: functions are not allowed in struct definitions + --> $DIR/fn-field-parse-error-ice.rs:4:17 + | +LL | inner : dyn fn () + | ^^ + | + = help: unlike in C++, Java, and C#, functions are declared in `impl` blocks + = help: see https://doc.rust-lang.org/book/ch05-03-method-syntax.html for more information + +error[E0412]: cannot find type `dyn` in this scope + --> $DIR/fn-field-parse-error-ice.rs:4:13 + | +LL | inner : dyn fn () + | ^^^ not found in this scope + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0412`. diff --git a/src/test/ui/prelude2021.rs b/src/test/ui/prelude2021.rs new file mode 100644 index 00000000000..3a9fd693228 --- /dev/null +++ b/src/test/ui/prelude2021.rs @@ -0,0 +1,7 @@ +// check-pass +// edition:2021 +// compile-flags: -Zunstable-options + +fn main() { + let _: u16 = 123i32.try_into().unwrap(); +} diff --git a/library/proc_macro/tests/test.rs b/src/test/ui/proc-macro/auxiliary/api/cmp.rs index d2e6b0bb809..5784a6e5d94 100644 --- a/library/proc_macro/tests/test.rs +++ b/src/test/ui/proc-macro/auxiliary/api/cmp.rs @@ -1,8 +1,10 @@ -#![feature(proc_macro_span)] +use proc_macro::{LineColumn, Punct, Spacing}; -use proc_macro::{LineColumn, Punct}; +pub fn test() { + test_line_column_ord(); + test_punct_eq(); +} -#[test] fn test_line_column_ord() { let line0_column0 = LineColumn { line: 0, column: 0 }; let line0_column1 = LineColumn { line: 0, column: 1 }; @@ -11,10 +13,9 @@ fn test_line_column_ord() { assert!(line0_column1 < line1_column0); } -#[test] fn test_punct_eq() { - // Good enough if it typechecks, since proc_macro::Punct can't exist in a test. - fn _check(punct: Punct) { - let _ = punct == ':'; - } + let colon_alone = Punct::new(':', Spacing::Alone); + assert_eq!(colon_alone, ':'); + let colon_joint = Punct::new(':', Spacing::Joint); + assert_eq!(colon_joint, ':'); } diff --git a/src/test/ui/proc-macro/auxiliary/api/mod.rs b/src/test/ui/proc-macro/auxiliary/api/mod.rs new file mode 100644 index 00000000000..739c25132e7 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/api/mod.rs @@ -0,0 +1,24 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] +#![crate_name = "proc_macro_api_tests"] +#![feature(proc_macro_span)] +#![deny(dead_code)] // catch if a test function is never called + +extern crate proc_macro; + +mod cmp; +mod parse; + +use proc_macro::TokenStream; + +#[proc_macro] +pub fn run(input: TokenStream) -> TokenStream { + assert!(input.is_empty()); + + cmp::test(); + parse::test(); + + TokenStream::new() +} diff --git a/src/test/ui/proc-macro/auxiliary/api/parse.rs b/src/test/ui/proc-macro/auxiliary/api/parse.rs new file mode 100644 index 00000000000..4105236b7f2 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/api/parse.rs @@ -0,0 +1,23 @@ +use proc_macro::Literal; + +pub fn test() { + test_parse_literal(); +} + +fn test_parse_literal() { + assert_eq!("1".parse::<Literal>().unwrap().to_string(), "1"); + assert_eq!("1.0".parse::<Literal>().unwrap().to_string(), "1.0"); + assert_eq!("'a'".parse::<Literal>().unwrap().to_string(), "'a'"); + assert_eq!("\"\n\"".parse::<Literal>().unwrap().to_string(), "\"\n\""); + assert_eq!("b\"\"".parse::<Literal>().unwrap().to_string(), "b\"\""); + assert_eq!("r##\"\"##".parse::<Literal>().unwrap().to_string(), "r##\"\"##"); + assert_eq!("10ulong".parse::<Literal>().unwrap().to_string(), "10ulong"); + + assert!("0 1".parse::<Literal>().is_err()); + assert!("'a".parse::<Literal>().is_err()); + assert!(" 0".parse::<Literal>().is_err()); + assert!("0 ".parse::<Literal>().is_err()); + assert!("/* comment */0".parse::<Literal>().is_err()); + assert!("0/* comment */".parse::<Literal>().is_err()); + assert!("0// comment".parse::<Literal>().is_err()); +} diff --git a/src/test/ui/proc-macro/test.rs b/src/test/ui/proc-macro/test.rs new file mode 100644 index 00000000000..c96aa73175f --- /dev/null +++ b/src/test/ui/proc-macro/test.rs @@ -0,0 +1,12 @@ +// check-pass +// aux-build:api/mod.rs + +//! This is for everything that *would* be a #[test] inside of libproc_macro, +//! except for the fact that proc_macro objects are not capable of existing +//! inside of an ordinary Rust test execution, only inside a macro. + +extern crate proc_macro_api_tests; + +proc_macro_api_tests::run!(); + +fn main() {} diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr index 381959b7ae4..db5042b40d8 100644 --- a/src/test/ui/question-mark-type-infer.stderr +++ b/src/test/ui/question-mark-type-infer.stderr @@ -1,11 +1,10 @@ -error[E0283]: type annotations needed +error[E0284]: type annotations needed --> $DIR/question-mark-type-infer.rs:12:21 | LL | l.iter().map(f).collect()? | ^^^^^^^ cannot infer type | - = note: cannot satisfy `_: Try` - = note: required by `into_result` + = note: cannot satisfy `<_ as Try>::Residual == _` help: consider specifying the type argument in the method call | LL | l.iter().map(f).collect::<B>()? @@ -13,4 +12,4 @@ LL | l.iter().map(f).collect::<B>()? error: aborting due to previous error -For more information about this error, try `rustc --explain E0283`. +For more information about this error, try `rustc --explain E0284`. diff --git a/src/test/ui/resolve/issue-85348.rs b/src/test/ui/resolve/issue-85348.rs new file mode 100644 index 00000000000..3a33c193408 --- /dev/null +++ b/src/test/ui/resolve/issue-85348.rs @@ -0,0 +1,12 @@ +// Checks whether shadowing a const parameter leads to an ICE (#85348). + +impl<const N: usize> ArrayWindowsExample { +//~^ ERROR: cannot find type `ArrayWindowsExample` in this scope [E0412] + fn next() { + let mut N; + //~^ ERROR: let bindings cannot shadow const parameters [E0530] + //~| ERROR: type annotations needed [E0282] + } +} + +fn main() {} diff --git a/src/test/ui/resolve/issue-85348.stderr b/src/test/ui/resolve/issue-85348.stderr new file mode 100644 index 00000000000..f475c26f32b --- /dev/null +++ b/src/test/ui/resolve/issue-85348.stderr @@ -0,0 +1,25 @@ +error[E0530]: let bindings cannot shadow const parameters + --> $DIR/issue-85348.rs:6:17 + | +LL | impl<const N: usize> ArrayWindowsExample { + | - the const parameter `N` is defined here +... +LL | let mut N; + | ^ cannot be named the same as a const parameter + +error[E0412]: cannot find type `ArrayWindowsExample` in this scope + --> $DIR/issue-85348.rs:3:22 + | +LL | impl<const N: usize> ArrayWindowsExample { + | ^^^^^^^^^^^^^^^^^^^ not found in this scope + +error[E0282]: type annotations needed + --> $DIR/issue-85348.rs:6:13 + | +LL | let mut N; + | ^^^^^ consider giving `N` a type + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0282, E0412, E0530. +For more information about an error, try `rustc --explain E0282`. diff --git a/src/test/ui/resolve/shadow-const-param.rs b/src/test/ui/resolve/shadow-const-param.rs new file mode 100644 index 00000000000..c435c16dc67 --- /dev/null +++ b/src/test/ui/resolve/shadow-const-param.rs @@ -0,0 +1,20 @@ +// Checks that const parameters cannot be shadowed with fresh bindings +// even in syntactically unambiguous contexts. See +// https://github.com/rust-lang/rust/issues/33118#issuecomment-233962221 + +fn foo<const N: i32>(i: i32) -> bool { + match i { + N @ _ => true, + //~^ ERROR: match bindings cannot shadow const parameters [E0530] + } +} + +fn bar<const N: i32>(i: i32) -> bool { + let N @ _ = 0; + //~^ ERROR: let bindings cannot shadow const parameters [E0530] + match i { + N @ _ => true, + } +} + +fn main() {} diff --git a/src/test/ui/resolve/shadow-const-param.stderr b/src/test/ui/resolve/shadow-const-param.stderr new file mode 100644 index 00000000000..fbd0d811000 --- /dev/null +++ b/src/test/ui/resolve/shadow-const-param.stderr @@ -0,0 +1,20 @@ +error[E0530]: match bindings cannot shadow const parameters + --> $DIR/shadow-const-param.rs:7:9 + | +LL | fn foo<const N: i32>(i: i32) -> bool { + | - the const parameter `N` is defined here +LL | match i { +LL | N @ _ => true, + | ^ cannot be named the same as a const parameter + +error[E0530]: let bindings cannot shadow const parameters + --> $DIR/shadow-const-param.rs:13:9 + | +LL | fn bar<const N: i32>(i: i32) -> bool { + | - the const parameter `N` is defined here +LL | let N @ _ = 0; + | ^ cannot be named the same as a const parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0530`. diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index 1adce5e0150..6985f1b71a8 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -502,10 +502,10 @@ LL | if (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | = help: the trait `Try` is not implemented for `bool` - = note: required by `into_result` + = note: required by `branch` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/disallowed-positions.rs:46:8 +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/disallowed-positions.rs:46:19 | LL | / fn nested_within_if_expr() { LL | | if &let 0 = 0 {} @@ -513,14 +513,14 @@ LL | | LL | | ... | LL | | if (let 0 = 0)? {} - | | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | | ^ cannot use the `?` operator in a function that returns `()` ... | LL | | if let true = let true = true {} LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `()` - = note: required by `from_error` + = help: the trait `FromResidual<_>` is not implemented for `()` + = note: required by `from_residual` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:56:8 @@ -660,7 +660,7 @@ LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` - = note: required by `into_result` + = note: required by `branch` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:96:11 @@ -690,10 +690,10 @@ LL | while (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | = help: the trait `Try` is not implemented for `bool` - = note: required by `into_result` + = note: required by `branch` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/disallowed-positions.rs:110:11 +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/disallowed-positions.rs:110:22 | LL | / fn nested_within_while_expr() { LL | | while &let 0 = 0 {} @@ -701,14 +701,14 @@ LL | | LL | | ... | LL | | while (let 0 = 0)? {} - | | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | | ^ cannot use the `?` operator in a function that returns `()` ... | LL | | while let true = let true = true {} LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `()` - = note: required by `from_error` + = help: the trait `FromResidual<_>` is not implemented for `()` + = note: required by `from_residual` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:120:11 @@ -848,7 +848,7 @@ LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` - = note: required by `into_result` + = note: required by `branch` error[E0614]: type `bool` cannot be dereferenced --> $DIR/disallowed-positions.rs:173:5 @@ -869,10 +869,10 @@ LL | (let 0 = 0)?; | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | = help: the trait `Try` is not implemented for `bool` - = note: required by `into_result` + = note: required by `branch` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/disallowed-positions.rs:183:5 +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/disallowed-positions.rs:183:16 | LL | / fn outside_if_and_while_expr() { LL | | &let 0 = 0; @@ -880,14 +880,14 @@ LL | | LL | | !let 0 = 0; ... | LL | | (let 0 = 0)?; - | | ^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | | ^ cannot use the `?` operator in a function that returns `()` ... | LL | | LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `()` - = note: required by `from_error` + = help: the trait `FromResidual<_>` is not implemented for `()` + = note: required by `from_residual` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:198:10 @@ -916,7 +916,7 @@ LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | = help: the trait `Try` is not implemented for `{integer}` - = note: required by `into_result` + = note: required by `branch` error: aborting due to 104 previous errors; 2 warnings emitted diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs index 58a2c271ecf..e0842bfa4cd 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/check-pass.rs @@ -8,6 +8,8 @@ // check-pass // only-x86_64 +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck #![feature(target_feature_11)] diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs index af35bc2014b..a59d7c2d784 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/closures-inherit-target_feature.rs @@ -1,6 +1,8 @@ // Tests #73631: closures inherit `#[target_feature]` annotations // check-pass +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck // only-x86_64 #![feature(target_feature_11)] diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr index 06cfdde3fb9..cf5815df56e 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.mir.stderr @@ -1,5 +1,5 @@ error[E0308]: mismatched types - --> $DIR/fn-ptr.rs:9:21 + --> $DIR/fn-ptr.rs:11:21 | LL | #[target_feature(enable = "sse2")] | ---------------------------------- `#[target_feature]` added here diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs index 3ecea5c5313..c95d4a08e48 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.rs @@ -1,3 +1,5 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck // only-x86_64 #![feature(target_feature_11)] diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr new file mode 100644 index 00000000000..cf5815df56e --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-ptr.thir.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/fn-ptr.rs:11:21 + | +LL | #[target_feature(enable = "sse2")] + | ---------------------------------- `#[target_feature]` added here +... +LL | let foo: fn() = foo; + | ---- ^^^ cannot coerce functions with `#[target_feature]` to safe function pointers + | | + | expected due to this + | + = note: expected fn pointer `fn()` + found fn item `fn() {foo}` + = note: functions with `#[target_feature]` can only be coerced to `unsafe` function pointers + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr index b9f748640b5..79273a1dcbf 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:21:5 + --> $DIR/safe-calls.rs:23:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -7,7 +7,7 @@ LL | sse2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:22:5 + --> $DIR/safe-calls.rs:24:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -15,7 +15,7 @@ LL | avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:23:5 + --> $DIR/safe-calls.rs:25:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -23,7 +23,7 @@ LL | Quux.avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:28:5 + --> $DIR/safe-calls.rs:30:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -31,7 +31,7 @@ LL | avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:29:5 + --> $DIR/safe-calls.rs:31:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -39,7 +39,7 @@ LL | Quux.avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:34:5 + --> $DIR/safe-calls.rs:36:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -47,7 +47,7 @@ LL | sse2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:35:5 + --> $DIR/safe-calls.rs:37:5 | LL | avx_bmi2(); | ^^^^^^^^^^ call to function with `#[target_feature]` @@ -55,7 +55,7 @@ LL | avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:36:5 + --> $DIR/safe-calls.rs:38:5 | LL | Quux.avx_bmi2(); | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` @@ -63,7 +63,7 @@ LL | Quux.avx_bmi2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:42:5 + --> $DIR/safe-calls.rs:44:5 | LL | sse2(); | ^^^^^^ call to function with `#[target_feature]` @@ -71,7 +71,7 @@ LL | sse2(); = note: can only be called if the required target features are available error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block - --> $DIR/safe-calls.rs:45:18 + --> $DIR/safe-calls.rs:47:18 | LL | const name: () = sse2(); | ^^^^^^ call to function with `#[target_feature]` diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs index 8da3affc447..de0b89f46ba 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.rs @@ -1,3 +1,5 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck // only-x86_64 #![feature(target_feature_11)] diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr new file mode 100644 index 00000000000..79273a1dcbf --- /dev/null +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/safe-calls.thir.stderr @@ -0,0 +1,83 @@ +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:23:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:24:5 + | +LL | avx_bmi2(); + | ^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:25:5 + | +LL | Quux.avx_bmi2(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:30:5 + | +LL | avx_bmi2(); + | ^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:31:5 + | +LL | Quux.avx_bmi2(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:36:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:37:5 + | +LL | avx_bmi2(); + | ^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:38:5 + | +LL | Quux.avx_bmi2(); + | ^^^^^^^^^^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:44:5 + | +LL | sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error[E0133]: call to function with `#[target_feature]` is unsafe and requires unsafe function or block + --> $DIR/safe-calls.rs:47:18 + | +LL | const name: () = sse2(); + | ^^^^^^ call to function with `#[target_feature]` + | + = note: can only be called if the required target features are available + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/running-with-no-runtime.rs b/src/test/ui/running-with-no-runtime.rs index c321e86dc18..c575a6bec8e 100644 --- a/src/test/ui/running-with-no-runtime.rs +++ b/src/test/ui/running-with-no-runtime.rs @@ -1,6 +1,8 @@ // run-pass // ignore-emscripten spawning processes is not supported // ignore-sgx no processes +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck #![feature(start)] diff --git a/src/test/ui/safe-extern-statics-mut.stderr b/src/test/ui/safe-extern-statics-mut.mir.stderr index 38803883414..cec5f9d9c9f 100644 --- a/src/test/ui/safe-extern-statics-mut.stderr +++ b/src/test/ui/safe-extern-statics-mut.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:11:13 + --> $DIR/safe-extern-statics-mut.rs:13:13 | LL | let b = B; | ^ use of mutable static @@ -7,7 +7,7 @@ LL | let b = B; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:12:14 + --> $DIR/safe-extern-statics-mut.rs:14:14 | LL | let rb = &B; | ^^ use of mutable static @@ -15,7 +15,7 @@ LL | let rb = &B; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:13:14 + --> $DIR/safe-extern-statics-mut.rs:15:14 | LL | let xb = XB; | ^^ use of mutable static @@ -23,7 +23,7 @@ LL | let xb = XB; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics-mut.rs:14:15 + --> $DIR/safe-extern-statics-mut.rs:16:15 | LL | let xrb = &XB; | ^^^ use of mutable static diff --git a/src/test/ui/safe-extern-statics-mut.rs b/src/test/ui/safe-extern-statics-mut.rs index 324fa443aa5..389a4589a71 100644 --- a/src/test/ui/safe-extern-statics-mut.rs +++ b/src/test/ui/safe-extern-statics-mut.rs @@ -1,4 +1,6 @@ // aux-build:extern-statics.rs +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck extern crate extern_statics; use extern_statics::*; diff --git a/src/test/ui/safe-extern-statics-mut.thir.stderr b/src/test/ui/safe-extern-statics-mut.thir.stderr new file mode 100644 index 00000000000..8e6d2805a0b --- /dev/null +++ b/src/test/ui/safe-extern-statics-mut.thir.stderr @@ -0,0 +1,35 @@ +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics-mut.rs:13:13 + | +LL | let b = B; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics-mut.rs:14:15 + | +LL | let rb = &B; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics-mut.rs:15:14 + | +LL | let xb = XB; + | ^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics-mut.rs:16:16 + | +LL | let xrb = &XB; + | ^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/safe-extern-statics.stderr b/src/test/ui/safe-extern-statics.mir.stderr index b42572ea3ee..102abd0816f 100644 --- a/src/test/ui/safe-extern-statics.stderr +++ b/src/test/ui/safe-extern-statics.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics.rs:11:13 + --> $DIR/safe-extern-statics.rs:13:13 | LL | let a = A; | ^ use of extern static @@ -7,7 +7,7 @@ LL | let a = A; = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics.rs:12:14 + --> $DIR/safe-extern-statics.rs:14:14 | LL | let ra = &A; | ^^ use of extern static @@ -15,7 +15,7 @@ LL | let ra = &A; = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics.rs:13:14 + --> $DIR/safe-extern-statics.rs:15:14 | LL | let xa = XA; | ^^ use of extern static @@ -23,7 +23,7 @@ LL | let xa = XA; = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior error[E0133]: use of extern static is unsafe and requires unsafe function or block - --> $DIR/safe-extern-statics.rs:14:15 + --> $DIR/safe-extern-statics.rs:16:15 | LL | let xra = &XA; | ^^^ use of extern static diff --git a/src/test/ui/safe-extern-statics.rs b/src/test/ui/safe-extern-statics.rs index 6fa4c4aaca5..0aa90c442ea 100644 --- a/src/test/ui/safe-extern-statics.rs +++ b/src/test/ui/safe-extern-statics.rs @@ -1,4 +1,6 @@ // aux-build:extern-statics.rs +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck extern crate extern_statics; use extern_statics::*; diff --git a/src/test/ui/safe-extern-statics.thir.stderr b/src/test/ui/safe-extern-statics.thir.stderr new file mode 100644 index 00000000000..7fd2182c4c6 --- /dev/null +++ b/src/test/ui/safe-extern-statics.thir.stderr @@ -0,0 +1,35 @@ +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics.rs:13:13 + | +LL | let a = A; + | ^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics.rs:14:15 + | +LL | let ra = &A; + | ^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics.rs:15:14 + | +LL | let xa = XA; + | ^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error[E0133]: use of extern static is unsafe and requires unsafe function or block + --> $DIR/safe-extern-statics.rs:16:16 + | +LL | let xra = &XA; + | ^^ use of extern static + | + = note: extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/sanitize/crt-static.rs b/src/test/ui/sanitize/crt-static.rs new file mode 100644 index 00000000000..f5dd2a40cc4 --- /dev/null +++ b/src/test/ui/sanitize/crt-static.rs @@ -0,0 +1,5 @@ +// compile-flags: -Z sanitizer=address -C target-feature=+crt-static --target x86_64-unknown-linux-gnu + +#![feature(no_core)] +#![no_core] +#![no_main] diff --git a/src/test/ui/sanitize/crt-static.stderr b/src/test/ui/sanitize/crt-static.stderr new file mode 100644 index 00000000000..3a9c636d760 --- /dev/null +++ b/src/test/ui/sanitize/crt-static.stderr @@ -0,0 +1,4 @@ +error: Sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static` + +error: aborting due to previous error + diff --git a/src/test/ui/simd/simd-intrinsic-generic-comparison.rs b/src/test/ui/simd/simd-intrinsic-generic-comparison.rs index 103132c18ae..da5c42a1a98 100644 --- a/src/test/ui/simd/simd-intrinsic-generic-comparison.rs +++ b/src/test/ui/simd/simd-intrinsic-generic-comparison.rs @@ -1,5 +1,7 @@ // run-pass // ignore-emscripten FIXME(#45351) hits an LLVM assert +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck #![feature(repr_simd, platform_intrinsics, concat_idents)] #![allow(non_camel_case_types)] diff --git a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr index 723c4a7a1fb..b251e8a438a 100644 --- a/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr +++ b/src/test/ui/single-use-lifetime/one-use-in-fn-argument-in-band.stderr @@ -1,11 +1,11 @@ -error: lifetime parameter `'b` only used once - --> $DIR/one-use-in-fn-argument-in-band.rs:11:22 +error: lifetime parameter `'a` only used once + --> $DIR/one-use-in-fn-argument-in-band.rs:11:10 | LL | fn a(x: &'a u32, y: &'b u32) { - | ^^- - | | - | this lifetime is only used here - | help: elide the single-use lifetime + | ^^- + | | + | this lifetime is only used here + | help: elide the single-use lifetime | note: the lint level is defined here --> $DIR/one-use-in-fn-argument-in-band.rs:4:9 @@ -13,14 +13,14 @@ note: the lint level is defined here LL | #![deny(single_use_lifetimes)] | ^^^^^^^^^^^^^^^^^^^^ -error: lifetime parameter `'a` only used once - --> $DIR/one-use-in-fn-argument-in-band.rs:11:10 +error: lifetime parameter `'b` only used once + --> $DIR/one-use-in-fn-argument-in-band.rs:11:22 | LL | fn a(x: &'a u32, y: &'b u32) { - | ^^- - | | - | this lifetime is only used here - | help: elide the single-use lifetime + | ^^- + | | + | this lifetime is only used here + | help: elide the single-use lifetime error: aborting due to 2 previous errors diff --git a/src/test/ui/span/lint-unused-unsafe.stderr b/src/test/ui/span/lint-unused-unsafe.mir.stderr index c35a3349121..c2adb7be7a2 100644 --- a/src/test/ui/span/lint-unused-unsafe.stderr +++ b/src/test/ui/span/lint-unused-unsafe.mir.stderr @@ -1,23 +1,23 @@ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:16:13 + --> $DIR/lint-unused-unsafe.rs:19:13 | LL | fn bad1() { unsafe {} } | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/lint-unused-unsafe.rs:4:9 + --> $DIR/lint-unused-unsafe.rs:7:9 | LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:17:13 + --> $DIR/lint-unused-unsafe.rs:20:13 | LL | fn bad2() { unsafe { bad1() } } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:18:20 + --> $DIR/lint-unused-unsafe.rs:21:20 | LL | unsafe fn bad3() { unsafe {} } | ---------------- ^^^^^^ unnecessary `unsafe` block @@ -25,13 +25,13 @@ LL | unsafe fn bad3() { unsafe {} } | because it's nested under this `unsafe` fn error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:19:13 + --> $DIR/lint-unused-unsafe.rs:22:13 | LL | fn bad4() { unsafe { callback(||{}) } } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:20:20 + --> $DIR/lint-unused-unsafe.rs:23:20 | LL | unsafe fn bad5() { unsafe { unsf() } } | ---------------- ^^^^^^ unnecessary `unsafe` block @@ -39,7 +39,7 @@ LL | unsafe fn bad5() { unsafe { unsf() } } | because it's nested under this `unsafe` fn error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:23:9 + --> $DIR/lint-unused-unsafe.rs:26:9 | LL | unsafe { // don't put the warning here | ------ because it's nested under this `unsafe` block @@ -47,7 +47,7 @@ LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:29:5 + --> $DIR/lint-unused-unsafe.rs:32:5 | LL | unsafe fn bad7() { | ---------------- because it's nested under this `unsafe` fn @@ -55,7 +55,7 @@ LL | unsafe { | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/lint-unused-unsafe.rs:30:9 + --> $DIR/lint-unused-unsafe.rs:33:9 | LL | unsafe fn bad7() { | ---------------- because it's nested under this `unsafe` fn diff --git a/src/test/ui/span/lint-unused-unsafe.rs b/src/test/ui/span/lint-unused-unsafe.rs index b6c4894d918..b889cc981ca 100644 --- a/src/test/ui/span/lint-unused-unsafe.rs +++ b/src/test/ui/span/lint-unused-unsafe.rs @@ -1,5 +1,8 @@ // Exercise the unused_unsafe attribute in some positive and negative cases +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck + #![allow(dead_code)] #![deny(unused_unsafe)] diff --git a/src/test/ui/span/lint-unused-unsafe.thir.stderr b/src/test/ui/span/lint-unused-unsafe.thir.stderr new file mode 100644 index 00000000000..dda45c3679a --- /dev/null +++ b/src/test/ui/span/lint-unused-unsafe.thir.stderr @@ -0,0 +1,66 @@ +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:19:13 + | +LL | fn bad1() { unsafe {} } + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/lint-unused-unsafe.rs:7:9 + | +LL | #![deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:20:13 + | +LL | fn bad2() { unsafe { bad1() } } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:21:20 + | +LL | unsafe fn bad3() { unsafe {} } + | ---------------- ^^^^^^ unnecessary `unsafe` block + | | + | because it's nested under this `unsafe` fn + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:22:13 + | +LL | fn bad4() { unsafe { callback(||{}) } } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:23:20 + | +LL | unsafe fn bad5() { unsafe { unsf() } } + | ---------------- ^^^^^^ unnecessary `unsafe` block + | | + | because it's nested under this `unsafe` fn + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:26:9 + | +LL | unsafe { // don't put the warning here + | ------ because it's nested under this `unsafe` block +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:33:9 + | +LL | unsafe { + | ------ because it's nested under this `unsafe` block +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/lint-unused-unsafe.rs:32:5 + | +LL | unsafe fn bad7() { + | ---------------- because it's nested under this `unsafe` fn +LL | unsafe { + | ^^^^^^ unnecessary `unsafe` block + +error: aborting due to 8 previous errors + diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr index fa59d7a0313..d2eea15f398 100644 --- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr +++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr @@ -1,4 +1,4 @@ -error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id::This) }, (I,)), [])` +error: cannot specialize on `Binder(ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[b09c]::Id::This) }, (I,)), [])` --> $DIR/repeated_projection_type.rs:19:1 | LL | / impl<I, V: Id<This = (I,)>> X for V { diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr index 99523f8eb64..c3e3f543d79 100644 --- a/src/test/ui/stability-attribute/generics-default-stability.stderr +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -169,10 +169,10 @@ LL | let _: Alias5<isize> = Alias5::Some(0); | ^^^^^^^^^^^^^ warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test - --> $DIR/generics-default-stability.rs:231:27 + --> $DIR/generics-default-stability.rs:231:34 | LL | let _: Enum4<isize> = Enum4::Some(1); - | ^^^^^^^^^^^ + | ^^^^ warning: use of deprecated enum `unstable_generic_param::Enum4`: test --> $DIR/generics-default-stability.rs:231:12 @@ -193,10 +193,10 @@ LL | let _: Enum4<usize> = ENUM4; | ^^^^^^^^^^^^ warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test - --> $DIR/generics-default-stability.rs:237:27 + --> $DIR/generics-default-stability.rs:237:34 | LL | let _: Enum4<isize> = Enum4::Some(0); - | ^^^^^^^^^^^ + | ^^^^ warning: use of deprecated enum `unstable_generic_param::Enum4`: test --> $DIR/generics-default-stability.rs:237:12 @@ -205,10 +205,10 @@ LL | let _: Enum4<isize> = Enum4::Some(0); | ^^^^^^^^^^^^ warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test - --> $DIR/generics-default-stability.rs:242:27 + --> $DIR/generics-default-stability.rs:242:34 | LL | let _: Enum5<isize> = Enum5::Some(1); - | ^^^^^^^^^^^ + | ^^^^ warning: use of deprecated enum `unstable_generic_param::Enum5`: test --> $DIR/generics-default-stability.rs:242:12 @@ -229,10 +229,10 @@ LL | let _: Enum5<usize> = ENUM5; | ^^^^^^^^^^^^ warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test - --> $DIR/generics-default-stability.rs:249:27 + --> $DIR/generics-default-stability.rs:249:34 | LL | let _: Enum5<isize> = Enum5::Some(0); - | ^^^^^^^^^^^ + | ^^^^ warning: use of deprecated enum `unstable_generic_param::Enum5`: test --> $DIR/generics-default-stability.rs:249:12 diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.stderr b/src/test/ui/static/static-mut-foreign-requires-unsafe.mir.stderr index e7ed0b710b2..a4659bc8712 100644 --- a/src/test/ui/static/static-mut-foreign-requires-unsafe.stderr +++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/static-mut-foreign-requires-unsafe.rs:6:5 + --> $DIR/static-mut-foreign-requires-unsafe.rs:9:5 | LL | a += 3; | ^^^^^^ use of mutable static @@ -7,7 +7,7 @@ LL | a += 3; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/static-mut-foreign-requires-unsafe.rs:7:5 + --> $DIR/static-mut-foreign-requires-unsafe.rs:10:5 | LL | a = 4; | ^^^^^ use of mutable static @@ -15,7 +15,7 @@ LL | a = 4; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/static-mut-foreign-requires-unsafe.rs:8:14 + --> $DIR/static-mut-foreign-requires-unsafe.rs:11:14 | LL | let _b = a; | ^ use of mutable static diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.rs b/src/test/ui/static/static-mut-foreign-requires-unsafe.rs index 90aa2537a82..4f96acb3375 100644 --- a/src/test/ui/static/static-mut-foreign-requires-unsafe.rs +++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + extern "C" { static mut a: i32; } diff --git a/src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr b/src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr new file mode 100644 index 00000000000..2c62d4d8f3b --- /dev/null +++ b/src/test/ui/static/static-mut-foreign-requires-unsafe.thir.stderr @@ -0,0 +1,27 @@ +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/static-mut-foreign-requires-unsafe.rs:9:5 + | +LL | a += 3; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/static-mut-foreign-requires-unsafe.rs:10:5 + | +LL | a = 4; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/static-mut-foreign-requires-unsafe.rs:11:14 + | +LL | let _b = a; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/static/static-mut-requires-unsafe.stderr b/src/test/ui/static/static-mut-requires-unsafe.mir.stderr index 85e468b333c..0d4ce056fc2 100644 --- a/src/test/ui/static/static-mut-requires-unsafe.stderr +++ b/src/test/ui/static/static-mut-requires-unsafe.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/static-mut-requires-unsafe.rs:4:5 + --> $DIR/static-mut-requires-unsafe.rs:7:5 | LL | a += 3; | ^^^^^^ use of mutable static @@ -7,7 +7,7 @@ LL | a += 3; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/static-mut-requires-unsafe.rs:5:5 + --> $DIR/static-mut-requires-unsafe.rs:8:5 | LL | a = 4; | ^^^^^ use of mutable static @@ -15,7 +15,7 @@ LL | a = 4; = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error[E0133]: use of mutable static is unsafe and requires unsafe function or block - --> $DIR/static-mut-requires-unsafe.rs:6:14 + --> $DIR/static-mut-requires-unsafe.rs:9:14 | LL | let _b = a; | ^ use of mutable static diff --git a/src/test/ui/static/static-mut-requires-unsafe.rs b/src/test/ui/static/static-mut-requires-unsafe.rs index 413b97e431d..ea3ba095007 100644 --- a/src/test/ui/static/static-mut-requires-unsafe.rs +++ b/src/test/ui/static/static-mut-requires-unsafe.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + static mut a: isize = 3; fn main() { diff --git a/src/test/ui/static/static-mut-requires-unsafe.thir.stderr b/src/test/ui/static/static-mut-requires-unsafe.thir.stderr new file mode 100644 index 00000000000..1a1cf14271a --- /dev/null +++ b/src/test/ui/static/static-mut-requires-unsafe.thir.stderr @@ -0,0 +1,27 @@ +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/static-mut-requires-unsafe.rs:7:5 + | +LL | a += 3; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/static-mut-requires-unsafe.rs:8:5 + | +LL | a = 4; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/static-mut-requires-unsafe.rs:9:14 + | +LL | let _b = a; + | ^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/suffixed-literal-meta.rs b/src/test/ui/suffixed-literal-meta.rs index 319264aec9c..a6531490c01 100644 --- a/src/test/ui/suffixed-literal-meta.rs +++ b/src/test/ui/suffixed-literal-meta.rs @@ -1,4 +1,4 @@ -#![feature(rustc_attrs, extended_key_value_attributes)] +#![feature(rustc_attrs)] #[rustc_dummy = 1usize] //~ ERROR: suffixed literals are not allowed in attributes #[rustc_dummy = 1u8] //~ ERROR: suffixed literals are not allowed in attributes diff --git a/src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs b/src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs new file mode 100644 index 00000000000..d71747f9687 --- /dev/null +++ b/src/test/ui/suggestions/auxiliary/proc-macro-type-error.rs @@ -0,0 +1,18 @@ +// force-host +// no-prefer-dynamic +#![crate_type = "proc-macro"] +#![feature(proc_macro_quote)] + +extern crate proc_macro; + +use proc_macro::{quote, TokenStream}; + +#[proc_macro_attribute] +pub fn hello(_: TokenStream, _: TokenStream) -> TokenStream { + quote!( + fn f(_: &mut i32) {} + fn g() { + f(123); + } + ) +} diff --git a/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr b/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr index df483b3912d..bd060c92cd4 100644 --- a/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr +++ b/src/test/ui/suggestions/imm-ref-trait-object-literal.stderr @@ -21,10 +21,10 @@ LL | fn foo<X: Trait>(_: X) {} | ----- required by this bound in `foo` ... LL | foo(s); - | ^ the trait `Trait` is not implemented for `S` - | - = help: the following implementations were found: - <&'a mut S as Trait> + | ^ + | | + | expected an implementor of trait `Trait` + | help: consider mutably borrowing here: `&mut s` error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/issue-72766.stderr b/src/test/ui/suggestions/issue-72766.stderr index 5c9c549fa07..eb67170d47c 100644 --- a/src/test/ui/suggestions/issue-72766.stderr +++ b/src/test/ui/suggestions/issue-72766.stderr @@ -5,7 +5,7 @@ LL | SadGirl {}.call()?; | ^^^^^^^^^^^^^^^^^^ the `?` operator cannot be applied to type `impl Future` | = help: the trait `Try` is not implemented for `impl Future` - = note: required by `into_result` + = note: required by `branch` help: consider `await`ing on the `Future` | LL | SadGirl {}.call().await?; diff --git a/src/test/ui/suggestions/issue-84973-2.rs b/src/test/ui/suggestions/issue-84973-2.rs new file mode 100644 index 00000000000..050cf8c64b3 --- /dev/null +++ b/src/test/ui/suggestions/issue-84973-2.rs @@ -0,0 +1,13 @@ +// A slight variation of issue-84973.rs. Here, a mutable borrow is +// required (and the obligation kind is different). + +trait Tr {} +impl Tr for &mut i32 {} + +fn foo<T: Tr>(i: T) {} + +fn main() { + let a: i32 = 32; + foo(a); + //~^ ERROR: the trait bound `i32: Tr` is not satisfied [E0277] +} diff --git a/src/test/ui/suggestions/issue-84973-2.stderr b/src/test/ui/suggestions/issue-84973-2.stderr new file mode 100644 index 00000000000..b6ed437b5ee --- /dev/null +++ b/src/test/ui/suggestions/issue-84973-2.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `i32: Tr` is not satisfied + --> $DIR/issue-84973-2.rs:11:9 + | +LL | fn foo<T: Tr>(i: T) {} + | -- required by this bound in `foo` +... +LL | foo(a); + | ^ + | | + | expected an implementor of trait `Tr` + | help: consider mutably borrowing here: `&mut a` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/issue-84973-blacklist.rs b/src/test/ui/suggestions/issue-84973-blacklist.rs new file mode 100644 index 00000000000..db954530b1b --- /dev/null +++ b/src/test/ui/suggestions/issue-84973-blacklist.rs @@ -0,0 +1,29 @@ +// Checks that certain traits for which we don't want to suggest borrowing +// are blacklisted and don't cause the suggestion to be issued. + +#![feature(generators)] + +fn f_copy<T: Copy>(t: T) {} +fn f_clone<T: Clone>(t: T) {} +fn f_unpin<T: Unpin>(t: T) {} +fn f_sized<T: Sized>(t: T) {} +fn f_send<T: Send>(t: T) {} + +struct S; + +fn main() { + f_copy("".to_string()); //~ ERROR: the trait bound `String: Copy` is not satisfied [E0277] + f_clone(S); //~ ERROR: the trait bound `S: Clone` is not satisfied [E0277] + f_unpin(static || { yield; }); + //~^ ERROR: cannot be unpinned [E0277] + + let cl = || (); + let ref_cl: &dyn Fn() -> () = &cl; + f_sized(*ref_cl); + //~^ ERROR: the size for values of type `dyn Fn()` cannot be known at compilation time [E0277] + //~| ERROR: the size for values of type `dyn Fn()` cannot be known at compilation time [E0277] + + use std::rc::Rc; + let rc = Rc::new(0); + f_send(rc); //~ ERROR: `Rc<{integer}>` cannot be sent between threads safely [E0277] +} diff --git a/src/test/ui/suggestions/issue-84973-blacklist.stderr b/src/test/ui/suggestions/issue-84973-blacklist.stderr new file mode 100644 index 00000000000..f1e6ef883ae --- /dev/null +++ b/src/test/ui/suggestions/issue-84973-blacklist.stderr @@ -0,0 +1,64 @@ +error[E0277]: the trait bound `String: Copy` is not satisfied + --> $DIR/issue-84973-blacklist.rs:15:12 + | +LL | fn f_copy<T: Copy>(t: T) {} + | ---- required by this bound in `f_copy` +... +LL | f_copy("".to_string()); + | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` + +error[E0277]: the trait bound `S: Clone` is not satisfied + --> $DIR/issue-84973-blacklist.rs:16:13 + | +LL | fn f_clone<T: Clone>(t: T) {} + | ----- required by this bound in `f_clone` +... +LL | f_clone(S); + | ^ the trait `Clone` is not implemented for `S` + +error[E0277]: `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:33]` cannot be unpinned + --> $DIR/issue-84973-blacklist.rs:17:5 + | +LL | fn f_unpin<T: Unpin>(t: T) {} + | ----- required by this bound in `f_unpin` +... +LL | f_unpin(static || { yield; }); + | ^^^^^^^ the trait `Unpin` is not implemented for `[static generator@$DIR/issue-84973-blacklist.rs:17:13: 17:33]` + | + = note: consider using `Box::pin` + +error[E0277]: the size for values of type `dyn Fn()` cannot be known at compilation time + --> $DIR/issue-84973-blacklist.rs:22:13 + | +LL | fn f_sized<T: Sized>(t: T) {} + | - required by this bound in `f_sized` +... +LL | f_sized(*ref_cl); + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Fn()` + +error[E0277]: `Rc<{integer}>` cannot be sent between threads safely + --> $DIR/issue-84973-blacklist.rs:28:12 + | +LL | fn f_send<T: Send>(t: T) {} + | ---- required by this bound in `f_send` +... +LL | f_send(rc); + | ^^ `Rc<{integer}>` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `Rc<{integer}>` + +error[E0277]: the size for values of type `dyn Fn()` cannot be known at compilation time + --> $DIR/issue-84973-blacklist.rs:22:5 + | +LL | f_sized(*ref_cl); + | ^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Fn()` + = note: all function arguments must have a statically known size + = help: unsized fn params are gated as an unstable feature + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/issue-84973-negative.rs b/src/test/ui/suggestions/issue-84973-negative.rs new file mode 100644 index 00000000000..f339251e57d --- /dev/null +++ b/src/test/ui/suggestions/issue-84973-negative.rs @@ -0,0 +1,12 @@ +// Checks that we only suggest borrowing if &T actually implements the trait. + +trait Tr {} +impl Tr for &f32 {} +fn bar<T: Tr>(t: T) {} + +fn main() { + let a = 0i32; + let b = 0.0f32; + bar(a); //~ ERROR: the trait bound `i32: Tr` is not satisfied [E0277] + bar(b); //~ ERROR: the trait bound `f32: Tr` is not satisfied [E0277] +} diff --git a/src/test/ui/suggestions/issue-84973-negative.stderr b/src/test/ui/suggestions/issue-84973-negative.stderr new file mode 100644 index 00000000000..94513eca0bf --- /dev/null +++ b/src/test/ui/suggestions/issue-84973-negative.stderr @@ -0,0 +1,24 @@ +error[E0277]: the trait bound `i32: Tr` is not satisfied + --> $DIR/issue-84973-negative.rs:10:9 + | +LL | fn bar<T: Tr>(t: T) {} + | -- required by this bound in `bar` +... +LL | bar(a); + | ^ the trait `Tr` is not implemented for `i32` + +error[E0277]: the trait bound `f32: Tr` is not satisfied + --> $DIR/issue-84973-negative.rs:11:9 + | +LL | fn bar<T: Tr>(t: T) {} + | -- required by this bound in `bar` +... +LL | bar(b); + | ^ + | | + | expected an implementor of trait `Tr` + | help: consider borrowing here: `&b` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/issue-84973.rs b/src/test/ui/suggestions/issue-84973.rs new file mode 100644 index 00000000000..42468478ed9 --- /dev/null +++ b/src/test/ui/suggestions/issue-84973.rs @@ -0,0 +1,33 @@ +// Checks whether borrowing is suggested when a trait bound is not satisfied +// for found type `T`, but is for `&/&mut T`. + +fn main() { + let f = Fancy{}; + let o = Other::new(f); + //~^ ERROR: the trait bound `Fancy: SomeTrait` is not satisfied [E0277] +} + +struct Fancy {} + +impl <'a> SomeTrait for &'a Fancy { +} + +trait SomeTrait {} + +struct Other<'a, G> { + a: &'a str, + g: G, +} + +// Broadly copied from https://docs.rs/petgraph/0.5.1/src/petgraph/dot.rs.html#70 +impl<'a, G> Other<'a, G> +where + G: SomeTrait, +{ + pub fn new(g: G) -> Self { + Other { + a: "hi", + g: g, + } + } +} diff --git a/src/test/ui/suggestions/issue-84973.stderr b/src/test/ui/suggestions/issue-84973.stderr new file mode 100644 index 00000000000..49fa94da859 --- /dev/null +++ b/src/test/ui/suggestions/issue-84973.stderr @@ -0,0 +1,15 @@ +error[E0277]: the trait bound `Fancy: SomeTrait` is not satisfied + --> $DIR/issue-84973.rs:6:24 + | +LL | let o = Other::new(f); + | ^ + | | + | expected an implementor of trait `SomeTrait` + | help: consider borrowing here: `&f` +... +LL | pub fn new(g: G) -> Self { + | ------------------------ required by `Other::<'a, G>::new` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/issue-85347.rs b/src/test/ui/suggestions/issue-85347.rs new file mode 100644 index 00000000000..f08e38689d6 --- /dev/null +++ b/src/test/ui/suggestions/issue-85347.rs @@ -0,0 +1,10 @@ +#![allow(incomplete_features)] +#![feature(generic_associated_types)] +use std::ops::Deref; +trait Foo { + type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>; + //~^ ERROR this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied + //~| HELP add missing +} + +fn main() {} diff --git a/src/test/ui/suggestions/issue-85347.stderr b/src/test/ui/suggestions/issue-85347.stderr new file mode 100644 index 00000000000..60594baa29c --- /dev/null +++ b/src/test/ui/suggestions/issue-85347.stderr @@ -0,0 +1,19 @@ +error[E0107]: this associated type takes 1 lifetime argument but 0 lifetime arguments were supplied + --> $DIR/issue-85347.rs:5:42 + | +LL | type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>; + | ^^^ expected 1 lifetime argument + | +note: associated type defined here, with 1 lifetime parameter: `'a` + --> $DIR/issue-85347.rs:5:10 + | +LL | type Bar<'a>: Deref<Target = <Self>::Bar<Target = Self>>; + | ^^^ -- +help: add missing lifetime argument + | +LL | type Bar<'a>: Deref<Target = <Self>::Bar<'a, Target = Self>>; + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs index 924bfd82eb8..66e1e77c905 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.rs @@ -17,7 +17,6 @@ fn main() { let fp = BufWriter::new(fp); //~^ ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied - //~| ERROR the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied writeln!(fp, "hello world").unwrap(); //~ ERROR the method } diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index a9b06214fe8..71b09d43612 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -11,19 +11,6 @@ error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satis --> $DIR/mut-borrow-needed-by-trait.rs:17:14 | LL | let fp = BufWriter::new(fp); - | ^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` - | - ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL - | -LL | pub struct BufWriter<W: Write> { - | ----- required by this bound in `BufWriter` - | - = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` - -error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:17:14 - | -LL | let fp = BufWriter::new(fp); | ^^^^^^^^^^^^^^^^^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | ::: $SRC_DIR/std/src/io/buffered/bufwriter.rs:LL:COL @@ -34,7 +21,7 @@ LL | pub struct BufWriter<W: Write> { = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` error[E0599]: the method `write_fmt` exists for struct `BufWriter<&dyn std::io::Write>`, but its trait bounds were not satisfied - --> $DIR/mut-borrow-needed-by-trait.rs:22:5 + --> $DIR/mut-borrow-needed-by-trait.rs:21:5 | LL | writeln!(fp, "hello world").unwrap(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method cannot be called on `BufWriter<&dyn std::io::Write>` due to unsatisfied trait bounds @@ -49,7 +36,7 @@ LL | pub struct BufWriter<W: Write> { which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` = note: this error originates in the macro `writeln` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0277, E0599. For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/suggestions/suggest-ref-macro.rs b/src/test/ui/suggestions/suggest-ref-macro.rs new file mode 100644 index 00000000000..6f780f32a14 --- /dev/null +++ b/src/test/ui/suggestions/suggest-ref-macro.rs @@ -0,0 +1,29 @@ +// run-check +// aux-build:proc-macro-type-error.rs + +extern crate proc_macro_type_error; + +use proc_macro_type_error::hello; + +#[hello] //~ERROR mismatched types +fn abc() {} + +fn x(_: &mut i32) {} + +macro_rules! bla { + () => { + x(123); + //~^ ERROR mismatched types + //~| SUGGESTION &mut 123 + }; + ($v:expr) => { + x($v) + } +} + +fn main() { + bla!(); + bla!(456); + //~^ ERROR mismatched types + //~| SUGGESTION &mut 456 +} diff --git a/src/test/ui/suggestions/suggest-ref-macro.stderr b/src/test/ui/suggestions/suggest-ref-macro.stderr new file mode 100644 index 00000000000..147001f0c94 --- /dev/null +++ b/src/test/ui/suggestions/suggest-ref-macro.stderr @@ -0,0 +1,34 @@ +error[E0308]: mismatched types + --> $DIR/suggest-ref-macro.rs:8:1 + | +LL | #[hello] + | ^^^^^^^^ expected `&mut i32`, found integer + | + = note: this error originates in the attribute macro `hello` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/suggest-ref-macro.rs:15:11 + | +LL | x(123); + | ^^^ + | | + | expected `&mut i32`, found integer + | help: consider mutably borrowing here: `&mut 123` +... +LL | bla!(); + | ------- in this macro invocation + | + = note: this error originates in the macro `bla` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/suggest-ref-macro.rs:26:10 + | +LL | bla!(456); + | ^^^ + | | + | expected `&mut i32`, found integer + | help: consider mutably borrowing here: `&mut 456` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/symbol-names/basic.legacy.stderr b/src/test/ui/symbol-names/basic.legacy.stderr index 3dd2b19fbf9..de4d35e261c 100644 --- a/src/test/ui/symbol-names/basic.legacy.stderr +++ b/src/test/ui/symbol-names/basic.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN5basic4main17h6c535bbea2051f85E) +error: symbol-name(_ZN5basic4main17hd75b915511563828E) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic::main::h6c535bbea2051f85) +error: demangling(basic::main::hd75b915511563828) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/basic.rs b/src/test/ui/symbol-names/basic.rs index bd107c10207..d871a4ee829 100644 --- a/src/test/ui/symbol-names/basic.rs +++ b/src/test/ui/symbol-names/basic.rs @@ -9,8 +9,8 @@ //[legacy]~^ ERROR symbol-name(_ZN5basic4main //[legacy]~| ERROR demangling(basic::main //[legacy]~| ERROR demangling-alt(basic::main) - //[v0]~^^^^ ERROR symbol-name(_RNvCs21hi0yVfW1J_5basic4main) - //[v0]~| ERROR demangling(basic[17891616a171812d]::main) + //[v0]~^^^^ ERROR symbol-name(_RNvCsj6j3mjPNGKx_5basic4main) + //[v0]~| ERROR demangling(basic[de7d5b6b69c71f37]::main) //[v0]~| ERROR demangling-alt(basic::main) #[rustc_def_path] //[legacy]~^ ERROR def-path(main) diff --git a/src/test/ui/symbol-names/basic.v0.stderr b/src/test/ui/symbol-names/basic.v0.stderr index 519efc9d7b4..e30fa6f66d5 100644 --- a/src/test/ui/symbol-names/basic.v0.stderr +++ b/src/test/ui/symbol-names/basic.v0.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_RNvCs21hi0yVfW1J_5basic4main) +error: symbol-name(_RNvCsj6j3mjPNGKx_5basic4main) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(basic[17891616a171812d]::main) +error: demangling(basic[de7d5b6b69c71f37]::main) --> $DIR/basic.rs:8:1 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/const-generics-demangling.rs b/src/test/ui/symbol-names/const-generics-demangling.rs index bd7e1c0f336..05c6b8352de 100644 --- a/src/test/ui/symbol-names/const-generics-demangling.rs +++ b/src/test/ui/symbol-names/const-generics-demangling.rs @@ -5,32 +5,32 @@ pub struct Unsigned<const F: u8>; #[rustc_symbol_name] -//~^ ERROR symbol-name(_RMCs21hi0yVfW1J_25const_generics_demanglingINtB0_8UnsignedKhb_E) -//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Unsigned<11: u8>>) +//~^ ERROR symbol-name(_RMCsaP8qXevlYG3_25const_generics_demanglingINtB0_8UnsignedKhb_E) +//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Unsigned<11: u8>>) //~| ERROR demangling-alt(<const_generics_demangling::Unsigned<11>>) impl Unsigned<11> {} pub struct Signed<const F: i16>; #[rustc_symbol_name] -//~^ ERROR symbol-name(_RMs_Cs21hi0yVfW1J_25const_generics_demanglingINtB2_6SignedKsn98_E) -//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Signed<-152: i16>>) +//~^ ERROR symbol-name(_RMs_CsaP8qXevlYG3_25const_generics_demanglingINtB2_6SignedKsn98_E) +//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Signed<-152: i16>>) //~| ERROR demangling-alt(<const_generics_demangling::Signed<-152>>) impl Signed<-152> {} pub struct Bool<const F: bool>; #[rustc_symbol_name] -//~^ ERROR symbol-name(_RMs0_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4BoolKb1_E) -//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Bool<true: bool>>) +//~^ ERROR symbol-name(_RMs0_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4BoolKb1_E) +//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Bool<true: bool>>) //~| ERROR demangling-alt(<const_generics_demangling::Bool<true>>) impl Bool<true> {} pub struct Char<const F: char>; #[rustc_symbol_name] -//~^ ERROR symbol-name(_RMs1_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4CharKc2202_E) -//~| ERROR demangling(<const_generics_demangling[17891616a171812d]::Char<'∂': char>>) +//~^ ERROR symbol-name(_RMs1_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4CharKc2202_E) +//~| ERROR demangling(<const_generics_demangling[7e153590edc26969]::Char<'∂': char>>) //~| ERROR demangling-alt(<const_generics_demangling::Char<'∂'>>) impl Char<'∂'> {} diff --git a/src/test/ui/symbol-names/const-generics-demangling.stderr b/src/test/ui/symbol-names/const-generics-demangling.stderr index 13995403f77..05c485d001f 100644 --- a/src/test/ui/symbol-names/const-generics-demangling.stderr +++ b/src/test/ui/symbol-names/const-generics-demangling.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_RMCs21hi0yVfW1J_25const_generics_demanglingINtB0_8UnsignedKhb_E) +error: symbol-name(_RMCsaP8qXevlYG3_25const_generics_demanglingINtB0_8UnsignedKhb_E) --> $DIR/const-generics-demangling.rs:7:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<const_generics_demangling[17891616a171812d]::Unsigned<11: u8>>) +error: demangling(<const_generics_demangling[7e153590edc26969]::Unsigned<11: u8>>) --> $DIR/const-generics-demangling.rs:7:1 | LL | #[rustc_symbol_name] @@ -16,13 +16,13 @@ error: demangling-alt(<const_generics_demangling::Unsigned<11>>) LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: symbol-name(_RMs_Cs21hi0yVfW1J_25const_generics_demanglingINtB2_6SignedKsn98_E) +error: symbol-name(_RMs_CsaP8qXevlYG3_25const_generics_demanglingINtB2_6SignedKsn98_E) --> $DIR/const-generics-demangling.rs:15:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<const_generics_demangling[17891616a171812d]::Signed<-152: i16>>) +error: demangling(<const_generics_demangling[7e153590edc26969]::Signed<-152: i16>>) --> $DIR/const-generics-demangling.rs:15:1 | LL | #[rustc_symbol_name] @@ -34,13 +34,13 @@ error: demangling-alt(<const_generics_demangling::Signed<-152>>) LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: symbol-name(_RMs0_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4BoolKb1_E) +error: symbol-name(_RMs0_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4BoolKb1_E) --> $DIR/const-generics-demangling.rs:23:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<const_generics_demangling[17891616a171812d]::Bool<true: bool>>) +error: demangling(<const_generics_demangling[7e153590edc26969]::Bool<true: bool>>) --> $DIR/const-generics-demangling.rs:23:1 | LL | #[rustc_symbol_name] @@ -52,13 +52,13 @@ error: demangling-alt(<const_generics_demangling::Bool<true>>) LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: symbol-name(_RMs1_Cs21hi0yVfW1J_25const_generics_demanglingINtB3_4CharKc2202_E) +error: symbol-name(_RMs1_CsaP8qXevlYG3_25const_generics_demanglingINtB3_4CharKc2202_E) --> $DIR/const-generics-demangling.rs:31:1 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<const_generics_demangling[17891616a171812d]::Char<'∂': char>>) +error: demangling(<const_generics_demangling[7e153590edc26969]::Char<'∂': char>>) --> $DIR/const-generics-demangling.rs:31:1 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index b0b31a57d06..960049be793 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -15,8 +15,8 @@ mod foo { //[legacy]~^ ERROR symbol-name(_ZN5impl13foo3Foo3bar //[legacy]~| ERROR demangling(impl1::foo::Foo::bar //[legacy]~| ERROR demangling-alt(impl1::foo::Foo::bar) - //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13fooNtB2_3Foo3bar) - //[v0]~| ERROR demangling(<impl1[17891616a171812d]::foo::Foo>::bar) + //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs2qSCrjELJET_5impl13fooNtB2_3Foo3bar) + //[v0]~| ERROR demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::bar) //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::bar) #[rustc_def_path] //[legacy]~^ ERROR def-path(foo::Foo::bar) @@ -33,8 +33,8 @@ mod bar { //[legacy]~^ ERROR symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz //[legacy]~| ERROR demangling(impl1::bar::<impl impl1::foo::Foo>::baz //[legacy]~| ERROR demangling-alt(impl1::bar::<impl impl1::foo::Foo>::baz) - //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13barNtNtB4_3foo3Foo3baz) - //[v0]~| ERROR demangling(<impl1[17891616a171812d]::foo::Foo>::baz) + //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs2qSCrjELJET_5impl13barNtNtB4_3foo3Foo3baz) + //[v0]~| ERROR demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::baz) //[v0]~| ERROR demangling-alt(<impl1::foo::Foo>::baz) #[rustc_def_path] //[legacy]~^ ERROR def-path(bar::<impl foo::Foo>::baz) @@ -63,8 +63,8 @@ fn main() { //[legacy]~^ ERROR symbol-name(_ZN209_$LT$$u5b$$RF$dyn$u20$impl1..Foo$u2b$Assoc$u20$$u3d$$u20$extern$u20$$u22$C$u22$$u20$fn$LP$$RF$u8$C$$u20$...$RP$$u2b$impl1..AutoTrait$u3b$$u20$3$u5d$$u20$as$u20$impl1..main..$u7b$$u7b$closure$u7d$$u7d$..Bar$GT$6method //[legacy]~| ERROR demangling(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method //[legacy]~| ERROR demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::AutoTrait; 3] as impl1::main::{{closure}}::Bar>::method) - //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs21hi0yVfW1J_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method) - //[v0]~| ERROR demangling(<[&dyn impl1[17891616a171812d]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[17891616a171812d]::AutoTrait; 3: usize] as impl1[17891616a171812d]::main::{closure#1}::Bar>::method) + //[v0]~^^^^ ERROR symbol-name(_RNvXNCNvCs2qSCrjELJET_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method) + //[v0]~| ERROR demangling(<[&dyn impl1[1c5860ab79c9e305]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[1c5860ab79c9e305]::AutoTrait; 3: usize] as impl1[1c5860ab79c9e305]::main::{closure#1}::Bar>::method) //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method) #[rustc_def_path] //[legacy]~^ ERROR def-path(<[&dyn Foo<Assoc = for<'r> extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{closure#1}::Bar>::method) diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr index e5b0deee36e..a7c3a389909 100644 --- a/src/test/ui/symbol-names/impl1.v0.stderr +++ b/src/test/ui/symbol-names/impl1.v0.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13fooNtB2_3Foo3bar) +error: symbol-name(_RNvMNtCs2qSCrjELJET_5impl13fooNtB2_3Foo3bar) --> $DIR/impl1.rs:14:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<impl1[17891616a171812d]::foo::Foo>::bar) +error: demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::bar) --> $DIR/impl1.rs:14:9 | LL | #[rustc_symbol_name] @@ -22,13 +22,13 @@ error: def-path(foo::Foo::bar) LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: symbol-name(_RNvMNtCs21hi0yVfW1J_5impl13barNtNtB4_3foo3Foo3baz) +error: symbol-name(_RNvMNtCs2qSCrjELJET_5impl13barNtNtB4_3foo3Foo3baz) --> $DIR/impl1.rs:32:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<impl1[17891616a171812d]::foo::Foo>::baz) +error: demangling(<impl1[1c5860ab79c9e305]::foo::Foo>::baz) --> $DIR/impl1.rs:32:9 | LL | #[rustc_symbol_name] @@ -46,13 +46,13 @@ error: def-path(bar::<impl foo::Foo>::baz) LL | #[rustc_def_path] | ^^^^^^^^^^^^^^^^^ -error: symbol-name(_RNvXNCNvCs21hi0yVfW1J_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method) +error: symbol-name(_RNvXNCNvCs2qSCrjELJET_5impl14mains_0ARDNtB6_3Foop5AssocFG_KCRL0_hvEuNtB6_9AutoTraitEL_j3_NtB2_3Bar6method) --> $DIR/impl1.rs:62:13 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<[&dyn impl1[17891616a171812d]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[17891616a171812d]::AutoTrait; 3: usize] as impl1[17891616a171812d]::main::{closure#1}::Bar>::method) +error: demangling(<[&dyn impl1[1c5860ab79c9e305]::Foo<Assoc = for<'a> extern "C" fn(&'a u8, ...)> + impl1[1c5860ab79c9e305]::AutoTrait; 3: usize] as impl1[1c5860ab79c9e305]::main::{closure#1}::Bar>::method) --> $DIR/impl1.rs:62:13 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/issue-60925.legacy.stderr b/src/test/ui/symbol-names/issue-60925.legacy.stderr index 83576783992..52d0c666398 100644 --- a/src/test/ui/symbol-names/issue-60925.legacy.stderr +++ b/src/test/ui/symbol-names/issue-60925.legacy.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h6244e5288326926aE) +error: symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo17h18eaa05e22e59176E) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h6244e5288326926a) +error: demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo::h18eaa05e22e59176) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/issue-60925.rs b/src/test/ui/symbol-names/issue-60925.rs index 3238eb1e579..a313c1ef383 100644 --- a/src/test/ui/symbol-names/issue-60925.rs +++ b/src/test/ui/symbol-names/issue-60925.rs @@ -22,8 +22,8 @@ mod foo { //[legacy]~^ ERROR symbol-name(_ZN11issue_609253foo37Foo$LT$issue_60925..llv$u6d$..Foo$GT$3foo //[legacy]~| ERROR demangling(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo //[legacy]~| ERROR demangling-alt(issue_60925::foo::Foo<issue_60925::llvm::Foo>::foo) - //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs21hi0yVfW1J_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo) - //[v0]~| ERROR demangling(<issue_60925[17891616a171812d]::foo::Foo<issue_60925[17891616a171812d]::llvm::Foo>>::foo) + //[v0]~^^^^ ERROR symbol-name(_RNvMNtCs8dUWfuENynB_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo) + //[v0]~| ERROR demangling(<issue_60925[5fcbb46c6fac4139]::foo::Foo<issue_60925[5fcbb46c6fac4139]::llvm::Foo>>::foo) //[v0]~| ERROR demangling-alt(<issue_60925::foo::Foo<issue_60925::llvm::Foo>>::foo) pub(crate) fn foo() { for _ in 0..0 { diff --git a/src/test/ui/symbol-names/issue-60925.v0.stderr b/src/test/ui/symbol-names/issue-60925.v0.stderr index 6a5885e1ea3..5d99abff59a 100644 --- a/src/test/ui/symbol-names/issue-60925.v0.stderr +++ b/src/test/ui/symbol-names/issue-60925.v0.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_RNvMNtCs21hi0yVfW1J_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo) +error: symbol-name(_RNvMNtCs8dUWfuENynB_11issue_609253fooINtB2_3FooNtNtB4_4llvm3FooE3foo) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<issue_60925[17891616a171812d]::foo::Foo<issue_60925[17891616a171812d]::llvm::Foo>>::foo) +error: demangling(<issue_60925[5fcbb46c6fac4139]::foo::Foo<issue_60925[5fcbb46c6fac4139]::llvm::Foo>>::foo) --> $DIR/issue-60925.rs:21:9 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/issue-75326.rs b/src/test/ui/symbol-names/issue-75326.rs index 4d061cafef3..0f721fc1f89 100644 --- a/src/test/ui/symbol-names/issue-75326.rs +++ b/src/test/ui/symbol-names/issue-75326.rs @@ -42,8 +42,8 @@ where //[legacy]~^ ERROR symbol-name(_ZN72_$LT$issue_75326..Foo$LT$I$C$E$GT$$u20$as$u20$issue_75326..Iterator2$GT$4next //[legacy]~| ERROR demangling(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next //[legacy]~| ERROR demangling-alt(<issue_75326::Foo<I,E> as issue_75326::Iterator2>::next) - //[v0]~^^^^ ERROR symbol-name(_RNvXINICs21hi0yVfW1J_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_) - //[v0]~| ERROR demangling(<issue_75326[17891616a171812d]::Foo<_, _> as issue_75326[17891616a171812d]::Iterator2>::next) + //[v0]~^^^^ ERROR symbol-name(_RNvXINICsiMBouZZ1iuD_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_) + //[v0]~| ERROR demangling(<issue_75326[dac9b7624645f95d]::Foo<_, _> as issue_75326[dac9b7624645f95d]::Iterator2>::next) //[v0]~| ERROR demangling-alt(<issue_75326::Foo<_, _> as issue_75326::Iterator2>::next) fn next(&mut self) -> Option<Self::Item> { self.find(|_| true) diff --git a/src/test/ui/symbol-names/issue-75326.v0.stderr b/src/test/ui/symbol-names/issue-75326.v0.stderr index 98844aafb65..093ba8c8576 100644 --- a/src/test/ui/symbol-names/issue-75326.v0.stderr +++ b/src/test/ui/symbol-names/issue-75326.v0.stderr @@ -1,10 +1,10 @@ -error: symbol-name(_RNvXINICs21hi0yVfW1J_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_) +error: symbol-name(_RNvXINICsiMBouZZ1iuD_11issue_75326s_0pppEINtB5_3FooppENtB5_9Iterator24nextB5_) --> $DIR/issue-75326.rs:41:5 | LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: demangling(<issue_75326[17891616a171812d]::Foo<_, _> as issue_75326[17891616a171812d]::Iterator2>::next) +error: demangling(<issue_75326[dac9b7624645f95d]::Foo<_, _> as issue_75326[dac9b7624645f95d]::Iterator2>::next) --> $DIR/issue-75326.rs:41:5 | LL | #[rustc_symbol_name] diff --git a/src/test/ui/symbol-names/trait-objects.rs b/src/test/ui/symbol-names/trait-objects.rs new file mode 100644 index 00000000000..cea1a89d757 --- /dev/null +++ b/src/test/ui/symbol-names/trait-objects.rs @@ -0,0 +1,48 @@ +// Ensure that trait objects don't include more than one binder. See #83611 + +// build-fail +// revisions: v0 +//[v0]compile-flags: -Z symbol-mangling-version=v0 +//[v0]normalize-stderr-test: "Cs.*?_" -> "CRATE_HASH" +//[v0]normalize-stderr-test: "core\[.*?\]" -> "core[HASH]" + +#![feature(rustc_attrs)] + +trait Bar { + fn method(&self) {} +} + +impl Bar for &dyn FnMut(&u8) { + #[rustc_symbol_name] + //[v0]~^ ERROR symbol-name + //[v0]~| ERROR demangling + //[v0]~| ERROR demangling-alt + fn method(&self) {} +} + +trait Foo { + fn method(&self) {} +} + +impl Foo for &(dyn FnMut(&u8) + for<'b> Send) { + #[rustc_symbol_name] + //[v0]~^ ERROR symbol-name + //[v0]~| ERROR demangling + //[v0]~| ERROR demangling-alt + fn method(&self) {} +} + +trait Baz { + fn method(&self) {} +} + +impl Baz for &(dyn for<'b> Send + FnMut(&u8)) { + #[rustc_symbol_name] + //[v0]~^ ERROR symbol-name + //[v0]~| ERROR demangling + //[v0]~| ERROR demangling-alt + fn method(&self) {} +} + +fn main() { +} diff --git a/src/test/ui/symbol-names/trait-objects.v0.stderr b/src/test/ui/symbol-names/trait-objects.v0.stderr new file mode 100644 index 00000000000..5ada82dfb2d --- /dev/null +++ b/src/test/ui/symbol-names/trait-objects.v0.stderr @@ -0,0 +1,56 @@ +error: symbol-name(_RNvXCRATE_HASH13trait_objectsRDG_INtNtNtCRATE_HASH4core3ops8function5FnMutTRL0_hEEp6OutputuEL_NtB2_3Bar6method) + --> $DIR/trait-objects.rs:16:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects[3f8b57f879016e18]::Bar>::method) + --> $DIR/trait-objects.rs:16:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> as trait_objects::Bar>::method) + --> $DIR/trait-objects.rs:16:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RNvXs_CRATE_HASH13trait_objectsRDG_INtNtNtCRATE_HASH4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtBI_6marker4SendEL_NtB4_3Foo6method) + --> $DIR/trait-objects.rs:28:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3f8b57f879016e18]::Foo>::method) + --> $DIR/trait-objects.rs:28:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Foo>::method) + --> $DIR/trait-objects.rs:28:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: symbol-name(_RNvXs0_CRATE_HASH13trait_objectsRDG_INtNtNtCRATE_HASH4core3ops8function5FnMutTRL0_hEEp6OutputuNtNtBJ_6marker4SendEL_NtB5_3Baz6method) + --> $DIR/trait-objects.rs:40:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling(<&dyn for<'a> core[HASH]::ops::function::FnMut<(&'a u8,), Output = ()> + core[HASH]::marker::Send as trait_objects[3f8b57f879016e18]::Baz>::method) + --> $DIR/trait-objects.rs:40:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: demangling-alt(<&dyn for<'a> core::ops::function::FnMut<(&'a u8,), Output = ()> + core::marker::Send as trait_objects::Baz>::method) + --> $DIR/trait-objects.rs:40:5 + | +LL | #[rustc_symbol_name] + | ^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 9 previous errors + diff --git a/src/test/ui/target-feature/wasm-safe.rs b/src/test/ui/target-feature/wasm-safe.rs new file mode 100644 index 00000000000..4b868684a52 --- /dev/null +++ b/src/test/ui/target-feature/wasm-safe.rs @@ -0,0 +1,44 @@ +// only-wasm32 +// check-pass + +#![feature(wasm_target_feature)] +#![allow(dead_code)] + +#[target_feature(enable = "nontrapping-fptoint")] +fn foo() {} + +#[target_feature(enable = "nontrapping-fptoint")] +extern "C" fn bar() {} + +trait A { + fn foo(); + fn bar(&self); +} + +struct B; + +impl B { + #[target_feature(enable = "nontrapping-fptoint")] + fn foo() {} + #[target_feature(enable = "nontrapping-fptoint")] + fn bar(&self) {} +} + +impl A for B { + #[target_feature(enable = "nontrapping-fptoint")] + fn foo() {} + #[target_feature(enable = "nontrapping-fptoint")] + fn bar(&self) {} +} + +fn no_features_enabled_on_this_function() { + bar(); + foo(); + B.bar(); + B::foo(); + <B as A>::foo(); + <B as A>::bar(&B); +} + +#[target_feature(enable = "nontrapping-fptoint")] +fn main() {} diff --git a/src/test/ui/thread-local-static.rs b/src/test/ui/thread-local-static.rs new file mode 100644 index 00000000000..c7fee9e6b4c --- /dev/null +++ b/src/test/ui/thread-local-static.rs @@ -0,0 +1,16 @@ +// edition:2018 + +#![feature(thread_local)] +#![feature(const_swap)] +#[thread_local] +static mut STATIC_VAR_2: [u32; 8] = [4; 8]; +const fn g(x: &mut [u32; 8]) { + //~^ ERROR mutable references are not allowed + std::mem::swap(x, &mut STATIC_VAR_2) + //~^ ERROR thread-local statics cannot be accessed + //~| ERROR mutable references are not allowed + //~| ERROR use of mutable static is unsafe + //~| constant functions cannot refer to statics +} + +fn main() {} diff --git a/src/test/ui/thread-local-static.stderr b/src/test/ui/thread-local-static.stderr new file mode 100644 index 00000000000..08bf593a5a7 --- /dev/null +++ b/src/test/ui/thread-local-static.stderr @@ -0,0 +1,44 @@ +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/thread-local-static.rs:7:12 + | +LL | const fn g(x: &mut [u32; 8]) { + | ^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0625]: thread-local statics cannot be accessed at compile-time + --> $DIR/thread-local-static.rs:9:28 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^ + +error[E0013]: constant functions cannot refer to statics + --> $DIR/thread-local-static.rs:9:28 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^ + | + = help: consider extracting the value of the `static` to a `const`, and referring to that + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/thread-local-static.rs:9:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #57349 <https://github.com/rust-lang/rust/issues/57349> for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0133]: use of mutable static is unsafe and requires unsafe function or block + --> $DIR/thread-local-static.rs:9:23 + | +LL | std::mem::swap(x, &mut STATIC_VAR_2) + | ^^^^^^^^^^^^^^^^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0013, E0133, E0658. +For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/traits/alias/style_lint.rs b/src/test/ui/traits/alias/style_lint.rs new file mode 100644 index 00000000000..33be20054b5 --- /dev/null +++ b/src/test/ui/traits/alias/style_lint.rs @@ -0,0 +1,8 @@ +// check-pass + +#![feature(trait_alias)] + +trait Foo = std::fmt::Display + std::fmt::Debug; +trait bar = std::fmt::Display + std::fmt::Debug; //~WARN trait alias `bar` should have an upper camel case name + +fn main() {} diff --git a/src/test/ui/traits/alias/style_lint.stderr b/src/test/ui/traits/alias/style_lint.stderr new file mode 100644 index 00000000000..91e2ea90eb9 --- /dev/null +++ b/src/test/ui/traits/alias/style_lint.stderr @@ -0,0 +1,10 @@ +warning: trait alias `bar` should have an upper camel case name + --> $DIR/style_lint.rs:6:7 + | +LL | trait bar = std::fmt::Display + std::fmt::Debug; + | ^^^ help: convert the identifier to upper camel case: `Bar` + | + = note: `#[warn(non_camel_case_types)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/ui/traits/inductive-overflow/lifetime.rs b/src/test/ui/traits/inductive-overflow/lifetime.rs index e23dfa57cd0..b75da1b512d 100644 --- a/src/test/ui/traits/inductive-overflow/lifetime.rs +++ b/src/test/ui/traits/inductive-overflow/lifetime.rs @@ -26,4 +26,6 @@ fn main() { // Should only be a few notes. is_send::<X<C<'static>>>(); //~^ ERROR overflow evaluating + //~| 2 redundant requirements hidden + //~| required because of } diff --git a/src/test/ui/traits/inductive-overflow/lifetime.stderr b/src/test/ui/traits/inductive-overflow/lifetime.stderr index 752154b35ca..cc913930395 100644 --- a/src/test/ui/traits/inductive-overflow/lifetime.stderr +++ b/src/test/ui/traits/inductive-overflow/lifetime.stderr @@ -7,11 +7,13 @@ LL | fn is_send<S: NotAuto>() {} LL | is_send::<X<C<'static>>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^ | -note: required because of the requirements on the impl of `NotAuto` for `X<C<'static>>` +note: required because of the requirements on the impl of `NotAuto` for `X<C<'_>>` --> $DIR/lifetime.rs:19:12 | LL | impl<T: Y> NotAuto for X<T> where T::P: NotAuto {} | ^^^^^^^ ^^^^ + = note: 2 redundant requirements hidden + = note: required because of the requirements on the impl of `NotAuto` for `X<C<'static>>` error: aborting due to previous error diff --git a/src/test/ui/traits/safety-fn-body.stderr b/src/test/ui/traits/safety-fn-body.mir.stderr index 0aeb186828e..ea7b2048e83 100644 --- a/src/test/ui/traits/safety-fn-body.stderr +++ b/src/test/ui/traits/safety-fn-body.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/safety-fn-body.rs:11:9 + --> $DIR/safety-fn-body.rs:14:9 | LL | *self += 1; | ^^^^^^^^^^ dereference of raw pointer diff --git a/src/test/ui/traits/safety-fn-body.rs b/src/test/ui/traits/safety-fn-body.rs index df527747305..2cc4fe1b344 100644 --- a/src/test/ui/traits/safety-fn-body.rs +++ b/src/test/ui/traits/safety-fn-body.rs @@ -1,6 +1,9 @@ // Check that an unsafe impl does not imply that unsafe actions are // legal in the methods. +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + unsafe trait UnsafeTrait : Sized { fn foo(self) { } } diff --git a/src/test/ui/traits/safety-fn-body.thir.stderr b/src/test/ui/traits/safety-fn-body.thir.stderr new file mode 100644 index 00000000000..23696c32bef --- /dev/null +++ b/src/test/ui/traits/safety-fn-body.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/safety-fn-body.rs:14:9 + | +LL | *self += 1; + | ^^^^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/try-block/try-block-bad-type.rs b/src/test/ui/try-block/try-block-bad-type.rs index ef6e690e1bd..30ae96763c0 100644 --- a/src/test/ui/try-block/try-block-bad-type.rs +++ b/src/test/ui/try-block/try-block-bad-type.rs @@ -15,8 +15,7 @@ pub fn main() { let res: Result<i32, i32> = try { }; //~ ERROR type mismatch let res: () = try { }; - //~^ ERROR the trait bound `(): Try` is not satisfied - //~| ERROR the trait bound `(): Try` is not satisfied + //~^ ERROR a `try` block must return `Result` or `Option` - let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: Try` is not satisfied + let res: i32 = try { 5 }; //~ ERROR a `try` block must return `Result` or `Option` } diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr index 75a42c0d6b7..ec5e91f10c2 100644 --- a/src/test/ui/try-block/try-block-bad-type.stderr +++ b/src/test/ui/try-block/try-block-bad-type.stderr @@ -7,43 +7,40 @@ LL | Err("")?; = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following implementations were found: <TryFromSliceError as From<Infallible>> - = note: required by `from` + = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, &str>>` for `Result<u32, TryFromSliceError>` + = note: required by `from_residual` -error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Ok == &str` +error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == &str` --> $DIR/try-block-bad-type.rs:12:9 | LL | "" | ^^ expected `i32`, found `&str` -error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Ok == ()` +error[E0271]: type mismatch resolving `<Result<i32, i32> as Try>::Output == ()` --> $DIR/try-block-bad-type.rs:15:39 | LL | let res: Result<i32, i32> = try { }; | ^ expected `i32`, found `()` -error[E0277]: the trait bound `(): Try` is not satisfied +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-block-bad-type.rs:17:25 | LL | let res: () = try { }; - | ^ the trait `Try` is not implemented for `()` + | ^ could not wrap the final value of the block as `()` doesn't implement `Try` | - = note: required by `from_ok` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_output` -error[E0277]: the trait bound `(): Try` is not satisfied - --> $DIR/try-block-bad-type.rs:17:25 - | -LL | let res: () = try { }; - | ^ the trait `Try` is not implemented for `()` - -error[E0277]: the trait bound `i32: Try` is not satisfied - --> $DIR/try-block-bad-type.rs:21:26 +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) + --> $DIR/try-block-bad-type.rs:20:26 | LL | let res: i32 = try { 5 }; - | ^ the trait `Try` is not implemented for `i32` + | ^ could not wrap the final value of the block as `i32` doesn't implement `Try` | - = note: required by `from_ok` + = help: the trait `Try` is not implemented for `i32` + = note: required by `from_output` -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors Some errors have detailed explanations: E0271, E0277. For more information about an error, try `rustc --explain E0271`. diff --git a/src/test/ui/try-block/try-block-in-while.rs b/src/test/ui/try-block/try-block-in-while.rs index 5d8748f1dd3..69793df525e 100644 --- a/src/test/ui/try-block/try-block-in-while.rs +++ b/src/test/ui/try-block/try-block-in-while.rs @@ -4,5 +4,5 @@ fn main() { while try { false } {} - //~^ ERROR the trait bound `bool: Try` is not satisfied + //~^ ERROR a `try` block must } diff --git a/src/test/ui/try-block/try-block-in-while.stderr b/src/test/ui/try-block/try-block-in-while.stderr index 75a4e8d065c..c83351d5c43 100644 --- a/src/test/ui/try-block/try-block-in-while.stderr +++ b/src/test/ui/try-block/try-block-in-while.stderr @@ -1,10 +1,11 @@ -error[E0277]: the trait bound `bool: Try` is not satisfied +error[E0277]: a `try` block must return `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-block-in-while.rs:6:17 | LL | while try { false } {} - | ^^^^^ the trait `Try` is not implemented for `bool` + | ^^^^^ could not wrap the final value of the block as `bool` doesn't implement `Try` | - = note: required by `from_ok` + = help: the trait `Try` is not implemented for `bool` + = note: required by `from_output` error: aborting due to previous error diff --git a/src/test/ui/try-block/try-block-type-error.stderr b/src/test/ui/try-block/try-block-type-error.stderr index df1441c83d4..3e9a584a551 100644 --- a/src/test/ui/try-block/try-block-type-error.stderr +++ b/src/test/ui/try-block/try-block-type-error.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<Option<f32> as Try>::Ok == {integer}` +error[E0271]: type mismatch resolving `<Option<f32> as Try>::Output == {integer}` --> $DIR/try-block-type-error.rs:10:9 | LL | 42 @@ -7,7 +7,7 @@ LL | 42 | expected `f32`, found integer | help: use a float literal: `42.0` -error[E0271]: type mismatch resolving `<Option<i32> as Try>::Ok == ()` +error[E0271]: type mismatch resolving `<Option<i32> as Try>::Output == ()` --> $DIR/try-block-type-error.rs:16:5 | LL | }; diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr deleted file mode 100644 index ecd12c430f1..00000000000 --- a/src/test/ui/try-on-option.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0277]: `?` couldn't convert the error to `()` - --> $DIR/try-on-option.rs:7:6 - | -LL | fn foo() -> Result<u32, ()> { - | --------------- expected `()` because of this -LL | let x: Option<u32> = None; -LL | x?; - | ^ the trait `From<NoneError>` is not implemented for `()` - | - = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `from` -help: consider converting the `Option<T>` into a `Result<T, _>` using `Option::ok_or` or `Option::ok_or_else` - | -LL | x.ok_or_else(|| /* error value */)?; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-on-option.rs:13:5 - | -LL | / fn bar() -> u32 { -LL | | let x: Option<u32> = None; -LL | | x?; - | | ^^ cannot use the `?` operator in a function that returns `u32` -LL | | 22 -LL | | } - | |_- this function should return `Result` or `Option` to accept `?` - | - = help: the trait `Try` is not implemented for `u32` - = note: required by `from_error` - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/try-operator-custom.rs b/src/test/ui/try-operator-custom.rs deleted file mode 100644 index 9993061ea61..00000000000 --- a/src/test/ui/try-operator-custom.rs +++ /dev/null @@ -1,63 +0,0 @@ -// run-pass - -#![feature(try_trait)] - -use std::ops::Try; - -enum MyResult<T, U> { - Awesome(T), - Terrible(U) -} - -impl<U, V> Try for MyResult<U, V> { - type Ok = U; - type Error = V; - - fn from_ok(u: U) -> MyResult<U, V> { - MyResult::Awesome(u) - } - - fn from_error(e: V) -> MyResult<U, V> { - MyResult::Terrible(e) - } - - fn into_result(self) -> Result<U, V> { - match self { - MyResult::Awesome(u) => Ok(u), - MyResult::Terrible(e) => Err(e), - } - } -} - -fn f(x: i32) -> Result<i32, String> { - if x == 0 { - Ok(42) - } else { - let y = g(x)?; - Ok(y) - } -} - -fn g(x: i32) -> MyResult<i32, String> { - let _y = f(x - 1)?; - MyResult::Terrible("Hello".to_owned()) -} - -fn h() -> MyResult<i32, String> { - let a: Result<i32, &'static str> = Err("Hello"); - let b = a?; - MyResult::Awesome(b) -} - -fn i() -> MyResult<i32, String> { - let a: MyResult<i32, &'static str> = MyResult::Terrible("Hello"); - let b = a?; - MyResult::Awesome(b) -} - -fn main() { - assert!(f(0) == Ok(42)); - assert!(f(10) == Err("Hello".to_owned())); - let _ = h(); - let _ = i(); -} diff --git a/src/test/ui/try-trait/bad-interconversion.rs b/src/test/ui/try-trait/bad-interconversion.rs new file mode 100644 index 00000000000..385f5510fb4 --- /dev/null +++ b/src/test/ui/try-trait/bad-interconversion.rs @@ -0,0 +1,48 @@ +#![feature(control_flow_enum)] + +use std::ops::ControlFlow; + +fn result_to_result() -> Result<u64, u8> { + Ok(Err(123_i32)?) + //~^ ERROR `?` couldn't convert the error to `u8` +} + +fn option_to_result() -> Result<u64, String> { + Some(3)?; + //~^ ERROR the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` + Ok(10) +} + +fn control_flow_to_result() -> Result<u64, String> { + Ok(ControlFlow::Break(123)?) + //~^ ERROR the `?` operator can only be used on `Result`s in a function that returns `Result` +} + +fn result_to_option() -> Option<u16> { + Some(Err("hello")?) + //~^ ERROR the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` +} + +fn control_flow_to_option() -> Option<u64> { + Some(ControlFlow::Break(123)?) + //~^ ERROR the `?` operator can only be used on `Option`s in a function that returns `Option` +} + +fn result_to_control_flow() -> ControlFlow<String> { + ControlFlow::Continue(Err("hello")?) + //~^ ERROR the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` +} + +fn option_to_control_flow() -> ControlFlow<u64> { + Some(3)?; + //~^ ERROR the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` + ControlFlow::Break(10) +} + +fn control_flow_to_control_flow() -> ControlFlow<i64> { + ControlFlow::Break(4_u8)?; + //~^ ERROR the `?` operator in a function that returns `ControlFlow<B, _>` can only be used on other `ControlFlow<B, _>`s + ControlFlow::Continue(()) +} + +fn main() {} diff --git a/src/test/ui/try-trait/bad-interconversion.stderr b/src/test/ui/try-trait/bad-interconversion.stderr new file mode 100644 index 00000000000..f5b315c2519 --- /dev/null +++ b/src/test/ui/try-trait/bad-interconversion.stderr @@ -0,0 +1,113 @@ +error[E0277]: `?` couldn't convert the error to `u8` + --> $DIR/bad-interconversion.rs:6:20 + | +LL | fn result_to_result() -> Result<u64, u8> { + | --------------- expected `u8` because of this +LL | Ok(Err(123_i32)?) + | ^ the trait `From<i32>` is not implemented for `u8` + | + = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait + = help: the following implementations were found: + <u8 as From<NonZeroU8>> + <u8 as From<bool>> + = note: required because of the requirements on the impl of `FromResidual<Result<Infallible, i32>>` for `Result<u64, u8>` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` + --> $DIR/bad-interconversion.rs:11:12 + | +LL | / fn option_to_result() -> Result<u64, String> { +LL | | Some(3)?; + | | ^ use `.ok_or(...)?` to provide an error compatible with `Result<u64, String>` +LL | | +LL | | Ok(10) +LL | | } + | |_- this function returns a `Result` + | + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u64, String>` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `Result`s in a function that returns `Result` + --> $DIR/bad-interconversion.rs:17:31 + | +LL | / fn control_flow_to_result() -> Result<u64, String> { +LL | | Ok(ControlFlow::Break(123)?) + | | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Result<u64, String>` +LL | | +LL | | } + | |_- this function returns a `Result` + | + = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Result<u64, String>` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` + --> $DIR/bad-interconversion.rs:22:22 + | +LL | / fn result_to_option() -> Option<u16> { +LL | | Some(Err("hello")?) + | | ^ use `.ok()?` if you want to discard the `Result<Infallible, &str>` error information +LL | | +LL | | } + | |_- this function returns an `Option` + | + = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `Option<u16>` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `Option`s in a function that returns `Option` + --> $DIR/bad-interconversion.rs:27:33 + | +LL | / fn control_flow_to_option() -> Option<u64> { +LL | | Some(ControlFlow::Break(123)?) + | | ^ this `?` produces `ControlFlow<{integer}, Infallible>`, which is incompatible with `Option<u64>` +LL | | +LL | | } + | |_- this function returns an `Option` + | + = help: the trait `FromResidual<ControlFlow<{integer}, Infallible>>` is not implemented for `Option<u64>` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` + --> $DIR/bad-interconversion.rs:32:39 + | +LL | / fn result_to_control_flow() -> ControlFlow<String> { +LL | | ControlFlow::Continue(Err("hello")?) + | | ^ this `?` produces `Result<Infallible, &str>`, which is incompatible with `ControlFlow<String>` +LL | | +LL | | } + | |_- this function returns a `ControlFlow` + | + = help: the trait `FromResidual<Result<Infallible, &str>>` is not implemented for `ControlFlow<String>` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `ControlFlow`s in a function that returns `ControlFlow` + --> $DIR/bad-interconversion.rs:37:12 + | +LL | / fn option_to_control_flow() -> ControlFlow<u64> { +LL | | Some(3)?; + | | ^ this `?` produces `Option<Infallible>`, which is incompatible with `ControlFlow<u64>` +LL | | +LL | | ControlFlow::Break(10) +LL | | } + | |_- this function returns a `ControlFlow` + | + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `ControlFlow<u64>` + = note: required by `from_residual` + +error[E0277]: the `?` operator in a function that returns `ControlFlow<B, _>` can only be used on other `ControlFlow<B, _>`s (with the same Break type) + --> $DIR/bad-interconversion.rs:43:29 + | +LL | / fn control_flow_to_control_flow() -> ControlFlow<i64> { +LL | | ControlFlow::Break(4_u8)?; + | | ^ this `?` produces `ControlFlow<u8, Infallible>`, which is incompatible with `ControlFlow<i64>` +LL | | +LL | | ControlFlow::Continue(()) +LL | | } + | |_- this function returns a `ControlFlow` + | + = help: the trait `FromResidual<ControlFlow<u8, Infallible>>` is not implemented for `ControlFlow<i64>` + = note: unlike `Result`, there's no `From`-conversion performed for `ControlFlow` + = note: required by `from_residual` + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/option-to-result.rs b/src/test/ui/try-trait/option-to-result.rs index 00e8b5244c5..45aaf361a9c 100644 --- a/src/test/ui/option-to-result.rs +++ b/src/test/ui/try-trait/option-to-result.rs @@ -2,12 +2,12 @@ fn main(){ } fn test_result() -> Result<(),()> { let a:Option<()> = Some(()); - a?;//~ ERROR `?` couldn't convert the error + a?;//~ ERROR the `?` operator can only be used Ok(()) } fn test_option() -> Option<i32>{ let a:Result<i32, i32> = Ok(5); - a?;//~ ERROR `?` couldn't convert the error + a?;//~ ERROR the `?` operator can only be used Some(5) } diff --git a/src/test/ui/try-trait/option-to-result.stderr b/src/test/ui/try-trait/option-to-result.stderr new file mode 100644 index 00000000000..9f7d80d4f23 --- /dev/null +++ b/src/test/ui/try-trait/option-to-result.stderr @@ -0,0 +1,31 @@ +error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` + --> $DIR/option-to-result.rs:5:6 + | +LL | / fn test_result() -> Result<(),()> { +LL | | let a:Option<()> = Some(()); +LL | | a?; + | | ^ use `.ok_or(...)?` to provide an error compatible with `Result<(), ()>` +LL | | Ok(()) +LL | | } + | |_- this function returns a `Result` + | + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<(), ()>` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used on `Option`s, not `Result`s, in a function that returns `Option` + --> $DIR/option-to-result.rs:11:6 + | +LL | / fn test_option() -> Option<i32>{ +LL | | let a:Result<i32, i32> = Ok(5); +LL | | a?; + | | ^ use `.ok()?` if you want to discard the `Result<Infallible, i32>` error information +LL | | Some(5) +LL | | } + | |_- this function returns an `Option` + | + = help: the trait `FromResidual<Result<Infallible, i32>>` is not implemented for `Option<i32>` + = note: required by `from_residual` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/try-trait/try-as-monad.rs b/src/test/ui/try-trait/try-as-monad.rs new file mode 100644 index 00000000000..cf09838b304 --- /dev/null +++ b/src/test/ui/try-trait/try-as-monad.rs @@ -0,0 +1,24 @@ +// run-pass + +#![feature(try_trait_v2)] + +use std::ops::Try; + +fn monad_unit<T: Try>(x: <T as Try>::Output) -> T { + T::from_output(x) +} + +fn monad_bind<T1: Try<Residual = R>, T2: Try<Residual = R>, R>( + mx: T1, + f: impl FnOnce(<T1 as Try>::Output) -> T2) +-> T2 { + let x = mx?; + f(x) +} + +fn main() { + let mx: Option<i32> = monad_unit(1); + let my = monad_bind(mx, |x| Some(x + 1)); + let mz = monad_bind(my, |x| Some(-x)); + assert_eq!(mz, Some(-2)); +} diff --git a/src/test/ui/try-on-option-diagnostics.rs b/src/test/ui/try-trait/try-on-option-diagnostics.rs index 63d17414c31..63d17414c31 100644 --- a/src/test/ui/try-on-option-diagnostics.rs +++ b/src/test/ui/try-trait/try-on-option-diagnostics.rs diff --git a/src/test/ui/try-on-option-diagnostics.stderr b/src/test/ui/try-trait/try-on-option-diagnostics.stderr index a71ee20aacf..e7c67c21bb3 100644 --- a/src/test/ui/try-on-option-diagnostics.stderr +++ b/src/test/ui/try-trait/try-on-option-diagnostics.stderr @@ -1,57 +1,57 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-on-option-diagnostics.rs:7:5 +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-on-option-diagnostics.rs:7:6 | LL | / fn a_function() -> u32 { LL | | let x: Option<u32> = None; LL | | x?; - | | ^^ cannot use the `?` operator in a function that returns `u32` + | | ^ cannot use the `?` operator in a function that returns `u32` LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `u32` - = note: required by `from_error` + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32` + = note: required by `from_residual` -error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-on-option-diagnostics.rs:14:9 +error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-on-option-diagnostics.rs:14:10 | LL | let a_closure = || { | _____________________- LL | | let x: Option<u32> = None; LL | | x?; - | | ^^ cannot use the `?` operator in a closure that returns `{integer}` + | | ^ cannot use the `?` operator in a closure that returns `{integer}` LL | | 22 LL | | }; | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `{integer}` - = note: required by `from_error` + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `{integer}` + = note: required by `from_residual` -error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-on-option-diagnostics.rs:26:13 +error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-on-option-diagnostics.rs:26:14 | LL | / fn a_method() { LL | | let x: Option<u32> = None; LL | | x?; - | | ^^ cannot use the `?` operator in a method that returns `()` + | | ^ cannot use the `?` operator in a method that returns `()` LL | | } | |_________- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `()` - = note: required by `from_error` + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()` + = note: required by `from_residual` -error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-on-option-diagnostics.rs:39:13 +error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-on-option-diagnostics.rs:39:14 | LL | / fn a_trait_method() { LL | | let x: Option<u32> = None; LL | | x?; - | | ^^ cannot use the `?` operator in a trait method that returns `()` + | | ^ cannot use the `?` operator in a trait method that returns `()` LL | | } | |_________- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `()` - = note: required by `from_error` + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `()` + = note: required by `from_residual` error: aborting due to 4 previous errors diff --git a/src/test/ui/try-on-option.rs b/src/test/ui/try-trait/try-on-option.rs index 5d94cee8e37..f2012936a11 100644 --- a/src/test/ui/try-on-option.rs +++ b/src/test/ui/try-trait/try-on-option.rs @@ -4,7 +4,7 @@ fn main() {} fn foo() -> Result<u32, ()> { let x: Option<u32> = None; - x?; //~ ERROR `?` couldn't convert the error + x?; //~ ERROR the `?` operator Ok(22) } diff --git a/src/test/ui/try-trait/try-on-option.stderr b/src/test/ui/try-trait/try-on-option.stderr new file mode 100644 index 00000000000..604baa8550b --- /dev/null +++ b/src/test/ui/try-trait/try-on-option.stderr @@ -0,0 +1,31 @@ +error[E0277]: the `?` operator can only be used on `Result`s, not `Option`s, in a function that returns `Result` + --> $DIR/try-on-option.rs:7:6 + | +LL | / fn foo() -> Result<u32, ()> { +LL | | let x: Option<u32> = None; +LL | | x?; + | | ^ use `.ok_or(...)?` to provide an error compatible with `Result<u32, ()>` +LL | | Ok(22) +LL | | } + | |_- this function returns a `Result` + | + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `Result<u32, ()>` + = note: required by `from_residual` + +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-on-option.rs:13:6 + | +LL | / fn bar() -> u32 { +LL | | let x: Option<u32> = None; +LL | | x?; + | | ^ cannot use the `?` operator in a function that returns `u32` +LL | | 22 +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `FromResidual<Option<Infallible>>` is not implemented for `u32` + = note: required by `from_residual` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/try-trait/try-operator-custom.rs b/src/test/ui/try-trait/try-operator-custom.rs new file mode 100644 index 00000000000..45636a7fced --- /dev/null +++ b/src/test/ui/try-trait/try-operator-custom.rs @@ -0,0 +1,91 @@ +// run-pass + +#![feature(control_flow_enum)] +#![feature(try_trait_v2)] + +use std::ops::{ControlFlow, FromResidual, Try}; + +enum MyResult<T, U> { + Awesome(T), + Terrible(U) +} + +enum Never {} + +impl<U, V> Try for MyResult<U, V> { + type Output = U; + type Residual = MyResult<Never, V>; + + fn from_output(u: U) -> MyResult<U, V> { + MyResult::Awesome(u) + } + + fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { + match self { + MyResult::Awesome(u) => ControlFlow::Continue(u), + MyResult::Terrible(e) => ControlFlow::Break(MyResult::Terrible(e)), + } + } +} + +impl<U, V, W> FromResidual<MyResult<Never, V>> for MyResult<U, W> where V: Into<W> { + fn from_residual(x: MyResult<Never, V>) -> Self { + match x { + MyResult::Awesome(u) => match u {}, + MyResult::Terrible(e) => MyResult::Terrible(e.into()), + } + } +} + +type ResultResidual<E> = Result<std::convert::Infallible, E>; + +impl<U, V, W> FromResidual<ResultResidual<V>> for MyResult<U, W> where V: Into<W> { + fn from_residual(x: ResultResidual<V>) -> Self { + match x { + Ok(v) => match v {} + Err(e) => MyResult::Terrible(e.into()), + } + } +} + +impl<U, V, W> FromResidual<MyResult<Never, V>> for Result<U, W> where V: Into<W> { + fn from_residual(x: MyResult<Never, V>) -> Self { + match x { + MyResult::Awesome(u) => match u {}, + MyResult::Terrible(e) => Err(e.into()), + } + } +} + +fn f(x: i32) -> Result<i32, String> { + if x == 0 { + Ok(42) + } else { + let y = g(x)?; + Ok(y) + } +} + +fn g(x: i32) -> MyResult<i32, String> { + let _y = f(x - 1)?; + MyResult::Terrible("Hello".to_owned()) +} + +fn h() -> MyResult<i32, String> { + let a: Result<i32, &'static str> = Err("Hello"); + let b = a?; + MyResult::Awesome(b) +} + +fn i() -> MyResult<i32, String> { + let a: MyResult<i32, &'static str> = MyResult::Terrible("Hello"); + let b = a?; + MyResult::Awesome(b) +} + +fn main() { + assert!(f(0) == Ok(42)); + assert!(f(10) == Err("Hello".to_owned())); + let _ = h(); + let _ = i(); +} diff --git a/src/test/ui/try-operator-on-main.rs b/src/test/ui/try-trait/try-operator-on-main.rs index e1b6cfbe5ae..3b364f7e7d3 100644 --- a/src/test/ui/try-operator-on-main.rs +++ b/src/test/ui/try-trait/try-operator-on-main.rs @@ -1,4 +1,4 @@ -#![feature(try_trait)] +#![feature(try_trait_v2)] use std::ops::Try; @@ -7,14 +7,13 @@ fn main() { std::fs::File::open("foo")?; //~ ERROR the `?` operator can only // a non-`Try` type on a non-`Try` fn - ()?; //~ ERROR the `?` operator can only + ()?; //~ ERROR the `?` operator can only be applied to + //~^ ERROR the `?` operator can only be used in a function that // an unrelated use of `Try` try_trait_generic::<()>(); //~ ERROR the trait bound } - - fn try_trait_generic<T: Try>() -> T { // and a non-`Try` object on a `Try` fn. ()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` diff --git a/src/test/ui/try-operator-on-main.stderr b/src/test/ui/try-trait/try-operator-on-main.stderr index be17de2fe7c..7d42c2e4d10 100644 --- a/src/test/ui/try-operator-on-main.stderr +++ b/src/test/ui/try-trait/try-operator-on-main.stderr @@ -1,18 +1,18 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) - --> $DIR/try-operator-on-main.rs:7:5 +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-operator-on-main.rs:7:31 | LL | / fn main() { LL | | // error for a `Try` type on a non-`Try` fn LL | | std::fs::File::open("foo")?; - | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()` + | | ^ cannot use the `?` operator in a function that returns `()` LL | | ... | LL | | try_trait_generic::<()>(); LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `Try` is not implemented for `()` - = note: required by `from_error` + = help: the trait `FromResidual<Result<Infallible, std::io::Error>>` is not implemented for `()` + = note: required by `from_residual` error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/try-operator-on-main.rs:10:5 @@ -21,10 +21,28 @@ LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | = help: the trait `Try` is not implemented for `()` - = note: required by `into_result` + = note: required by `branch` + +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `FromResidual`) + --> $DIR/try-operator-on-main.rs:10:7 + | +LL | / fn main() { +LL | | // error for a `Try` type on a non-`Try` fn +LL | | std::fs::File::open("foo")?; +LL | | +LL | | // a non-`Try` type on a non-`Try` fn +LL | | ()?; + | | ^ cannot use the `?` operator in a function that returns `()` +... | +LL | | try_trait_generic::<()>(); +LL | | } + | |_- this function should return `Result` or `Option` to accept `?` + | + = help: the trait `FromResidual<_>` is not implemented for `()` + = note: required by `from_residual` error[E0277]: the trait bound `(): Try` is not satisfied - --> $DIR/try-operator-on-main.rs:13:25 + --> $DIR/try-operator-on-main.rs:14:25 | LL | try_trait_generic::<()>(); | ^^ the trait `Try` is not implemented for `()` @@ -33,14 +51,14 @@ LL | fn try_trait_generic<T: Try>() -> T { | --- required by this bound in `try_trait_generic` error[E0277]: the `?` operator can only be applied to values that implement `Try` - --> $DIR/try-operator-on-main.rs:20:5 + --> $DIR/try-operator-on-main.rs:19:5 | LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | = help: the trait `Try` is not implemented for `()` - = note: required by `into_result` + = note: required by `branch` -error: aborting due to 4 previous errors +error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/try-poll.rs b/src/test/ui/try-trait/try-poll.rs index d42e51c7405..d42e51c7405 100644 --- a/src/test/ui/try-poll.rs +++ b/src/test/ui/try-trait/try-poll.rs diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr b/src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr index 0880136d71b..05b63a00dfb 100644 --- a/src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-74761.full_tait.stderr @@ -1,5 +1,5 @@ warning: the feature `type_alias_impl_trait` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-74761.rs:4:32 + --> $DIR/issue-74761.rs:3:32 | LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))] | ^^^^^^^^^^^^^^^^^^^^^ @@ -8,13 +8,13 @@ LL | #![cfg_attr(full_tait, feature(type_alias_impl_trait))] = note: see issue #63063 <https://github.com/rust-lang/rust/issues/63063> for more information error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-74761.rs:11:6 + --> $DIR/issue-74761.rs:10:6 | LL | impl<'a, 'b> A for () { | ^^ unconstrained lifetime parameter error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-74761.rs:11:10 + --> $DIR/issue-74761.rs:10:10 | LL | impl<'a, 'b> A for () { | ^^ unconstrained lifetime parameter diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr b/src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr index 20ebdd9cb50..ad111e23b15 100644 --- a/src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-74761.min_tait.stderr @@ -1,11 +1,11 @@ error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-74761.rs:11:6 + --> $DIR/issue-74761.rs:10:6 | LL | impl<'a, 'b> A for () { | ^^ unconstrained lifetime parameter error[E0207]: the lifetime parameter `'b` is not constrained by the impl trait, self type, or predicates - --> $DIR/issue-74761.rs:11:10 + --> $DIR/issue-74761.rs:10:10 | LL | impl<'a, 'b> A for () { | ^^ unconstrained lifetime parameter diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.rs b/src/test/ui/type-alias-impl-trait/issue-74761.rs index 66bb079b25a..bbc67ecc97a 100644 --- a/src/test/ui/type-alias-impl-trait/issue-74761.rs +++ b/src/test/ui/type-alias-impl-trait/issue-74761.rs @@ -1,4 +1,3 @@ -#![feature(member_constraints)] // revisions: min_tait full_tait #![feature(min_type_alias_impl_trait)] #![cfg_attr(full_tait, feature(type_alias_impl_trait))] diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr index 88322c3a0a6..33f762ccf63 100644 --- a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.stderr +++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/issue-45087-unreachable-unsafe.rs:3:5 + --> $DIR/issue-45087-unreachable-unsafe.rs:6:5 | LL | *(1 as *mut u32) = 42; | ^^^^^^^^^^^^^^^^^^^^^ dereference of raw pointer diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs index 5edf7a47e2f..071cea8fbd7 100644 --- a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs +++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + fn main() { return; *(1 as *mut u32) = 42; diff --git a/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr new file mode 100644 index 00000000000..73a113652b8 --- /dev/null +++ b/src/test/ui/unsafe/issue-45087-unreachable-unsafe.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/issue-45087-unreachable-unsafe.rs:6:5 + | +LL | *(1 as *mut u32) = 42; + | ^^^^^^^^^^^^^^^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs b/src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs new file mode 100644 index 00000000000..72f7b674777 --- /dev/null +++ b/src/test/ui/unsafe/issue-85435-unsafe-op-in-let-under-unsafe-under-closure.rs @@ -0,0 +1,27 @@ +// check-pass +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + +// This is issue #85435. But the real story is reflected in issue #85561, where +// a bug in the implementation of feature(capture_disjoint_fields) () was +// exposed to non-feature-gated code by a diagnostic changing PR that removed +// the gating in one case. + +// This test is double-checking that the case of interest continues to work as +// expected in the *absence* of that feature gate. At the time of this writing, +// enabling the feature gate will cause this test to fail. We obviously cannot +// stabilize that feature until it can correctly handle this test. + +fn main() { + let val: u8 = 5; + let u8_ptr: *const u8 = &val; + let _closure = || { + unsafe { + let tmp = *u8_ptr; + tmp + + // Just dereferencing and returning directly compiles fine: + // *u8_ptr + } + }; +} diff --git a/src/test/ui/unsafe/ranged_ints.stderr b/src/test/ui/unsafe/ranged_ints.mir.stderr index 4e43df495c0..f9ef7834e1e 100644 --- a/src/test/ui/unsafe/ranged_ints.stderr +++ b/src/test/ui/unsafe/ranged_ints.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block - --> $DIR/ranged_ints.rs:7:14 + --> $DIR/ranged_ints.rs:10:14 | LL | let _x = NonZero(0); | ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr diff --git a/src/test/ui/unsafe/ranged_ints.rs b/src/test/ui/unsafe/ranged_ints.rs index 0fa2da917e9..05efe87ba6e 100644 --- a/src/test/ui/unsafe/ranged_ints.rs +++ b/src/test/ui/unsafe/ranged_ints.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![feature(rustc_attrs)] #[rustc_layout_scalar_valid_range_start(1)] diff --git a/src/test/ui/unsafe/ranged_ints.thir.stderr b/src/test/ui/unsafe/ranged_ints.thir.stderr new file mode 100644 index 00000000000..f9ef7834e1e --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block + --> $DIR/ranged_ints.rs:10:14 + | +LL | let _x = NonZero(0); + | ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr + | + = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/ranged_ints_const.stderr b/src/test/ui/unsafe/ranged_ints_const.mir.stderr index 584ad40a92b..33d134c7ce5 100644 --- a/src/test/ui/unsafe/ranged_ints_const.stderr +++ b/src/test/ui/unsafe/ranged_ints_const.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block - --> $DIR/ranged_ints_const.rs:8:34 + --> $DIR/ranged_ints_const.rs:11:34 | LL | const fn foo() -> NonZero<u32> { NonZero(0) } | ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr diff --git a/src/test/ui/unsafe/ranged_ints_const.rs b/src/test/ui/unsafe/ranged_ints_const.rs index 8477772867e..472b0968150 100644 --- a/src/test/ui/unsafe/ranged_ints_const.rs +++ b/src/test/ui/unsafe/ranged_ints_const.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![feature(rustc_attrs)] #[rustc_layout_scalar_valid_range_start(1)] diff --git a/src/test/ui/unsafe/ranged_ints_const.thir.stderr b/src/test/ui/unsafe/ranged_ints_const.thir.stderr new file mode 100644 index 00000000000..33d134c7ce5 --- /dev/null +++ b/src/test/ui/unsafe/ranged_ints_const.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block + --> $DIR/ranged_ints_const.rs:11:34 + | +LL | const fn foo() -> NonZero<u32> { NonZero(0) } + | ^^^^^^^^^^ initializing type with `rustc_layout_scalar_valid_range` attr + | + = note: initializing a layout restricted type's field with a value outside the valid range is undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/ranged_ints_macro.rs b/src/test/ui/unsafe/ranged_ints_macro.rs index 9192ecfe196..8293d029951 100644 --- a/src/test/ui/unsafe/ranged_ints_macro.rs +++ b/src/test/ui/unsafe/ranged_ints_macro.rs @@ -1,4 +1,7 @@ // build-pass +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![feature(rustc_attrs)] macro_rules! apply { diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr index ad93267ca01..9a522fac65f 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.stderr +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.mir.stderr @@ -1,18 +1,18 @@ error: call to unsafe function is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:9:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5 | LL | unsf(); | ^^^^^^ call to unsafe function | note: the lint level is defined here - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:1:9 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9 | LL | #![deny(unsafe_op_in_unsafe_fn)] | ^^^^^^^^^^^^^^^^^^^^^^ = note: consult the function's documentation for information on how to avoid undefined behavior error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:11:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5 | LL | *PTR; | ^^^^ dereference of raw pointer @@ -20,7 +20,7 @@ LL | *PTR; = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: use of mutable static is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:13:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5 | LL | VOID = (); | ^^^^^^^^^ use of mutable static @@ -28,25 +28,25 @@ LL | VOID = (); = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5 | LL | unsafe {} | ^^^^^^ unnecessary `unsafe` block | note: the lint level is defined here - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:2:9 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:5:9 | LL | #![deny(unused_unsafe)] | ^^^^^^^^^^^^^ error: call to unsafe function is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:24:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5 | LL | unsf(); | ^^^^^^ call to unsafe function | note: the lint level is defined here - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:22:8 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8 | LL | #[deny(warnings)] | ^^^^^^^^ @@ -54,7 +54,7 @@ LL | #[deny(warnings)] = note: consult the function's documentation for information on how to avoid undefined behavior error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:26:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5 | LL | *PTR; | ^^^^ dereference of raw pointer @@ -62,7 +62,7 @@ LL | *PTR; = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior error: use of mutable static is unsafe and requires unsafe block (error E0133) - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:28:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5 | LL | VOID = (); | ^^^^^^^^^ use of mutable static @@ -70,13 +70,13 @@ LL | VOID = (); = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:30:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5 | LL | unsafe {} | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:44:14 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14 | LL | unsafe { unsafe { unsf() } } | ------ ^^^^^^ unnecessary `unsafe` block @@ -84,7 +84,7 @@ LL | unsafe { unsafe { unsf() } } | because it's nested under this `unsafe` block error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:55:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5 | LL | unsafe fn allow_level() { | ----------------------- because it's nested under this `unsafe` fn @@ -93,7 +93,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error: unnecessary `unsafe` block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:67:9 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9 | LL | unsafe fn nested_allow_level() { | ------------------------------ because it's nested under this `unsafe` fn @@ -102,7 +102,7 @@ LL | unsafe { unsf() } | ^^^^^^ unnecessary `unsafe` block error[E0133]: call to unsafe function is unsafe and requires unsafe block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:73:5 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5 | LL | unsf(); | ^^^^^^ call to unsafe function @@ -110,7 +110,7 @@ LL | unsf(); = note: consult the function's documentation for information on how to avoid undefined behavior error[E0133]: call to unsafe function is unsafe and requires unsafe function or block - --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:77:9 + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9 | LL | unsf(); | ^^^^^^ call to unsafe function diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs index c8400a6fc4d..7ca714b85c2 100644 --- a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Zthir-unsafeck + #![deny(unsafe_op_in_unsafe_fn)] #![deny(unused_unsafe)] diff --git a/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr new file mode 100644 index 00000000000..ad87690bb52 --- /dev/null +++ b/src/test/ui/unsafe/rfc-2585-unsafe_op_in_unsafe_fn.thir.stderr @@ -0,0 +1,122 @@ +error: call to unsafe function is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:12:5 + | +LL | unsf(); + | ^^^^^^ call to unsafe function + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:4:9 + | +LL | #![deny(unsafe_op_in_unsafe_fn)] + | ^^^^^^^^^^^^^^^^^^^^^^ + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:14:5 + | +LL | *PTR; + | ^^^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: use of mutable static is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:16:5 + | +LL | VOID = (); + | ^^^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:19:5 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:5:9 + | +LL | #![deny(unused_unsafe)] + | ^^^^^^^^^^^^^ + +error: call to unsafe function is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:27:5 + | +LL | unsf(); + | ^^^^^^ call to unsafe function + | +note: the lint level is defined here + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:25:8 + | +LL | #[deny(warnings)] + | ^^^^^^^^ + = note: `#[deny(unsafe_op_in_unsafe_fn)]` implied by `#[deny(warnings)]` + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: dereference of raw pointer is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:29:5 + | +LL | *PTR; + | ^^^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: use of mutable static is unsafe and requires unsafe block (error E0133) + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:31:5 + | +LL | VOID = (); + | ^^^^ use of mutable static + | + = note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior + +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:33:5 + | +LL | unsafe {} + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:47:14 + | +LL | unsafe { unsafe { unsf() } } + | ------ ^^^^^^ unnecessary `unsafe` block + | | + | because it's nested under this `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:58:5 + | +LL | unsafe fn allow_level() { + | ----------------------- because it's nested under this `unsafe` fn +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error: unnecessary `unsafe` block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:70:9 + | +LL | unsafe fn nested_allow_level() { + | ------------------------------ because it's nested under this `unsafe` fn +... +LL | unsafe { unsf() } + | ^^^^^^ unnecessary `unsafe` block + +error[E0133]: call to unsafe function is unsafe and requires unsafe block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:76:5 + | +LL | unsf(); + | ^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error[E0133]: call to unsafe function is unsafe and requires unsafe function or block + --> $DIR/rfc-2585-unsafe_op_in_unsafe_fn.rs:80:9 + | +LL | unsf(); + | ^^^^^^ call to unsafe function + | + = note: consult the function's documentation for information on how to avoid undefined behavior + +error: aborting due to 13 previous errors + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.mir.stderr index b2a30f81e05..fee645e4118 100644 --- a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.stderr +++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/unsafe-fn-assign-deref-ptr.rs:2:5 + --> $DIR/unsafe-fn-assign-deref-ptr.rs:5:5 | LL | *p = 0; | ^^^^^^ dereference of raw pointer diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs index 91264e790c8..a94e94375ae 100644 --- a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs +++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + fn f(p: *mut u8) { *p = 0; //~ ERROR dereference of raw pointer is unsafe return; diff --git a/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr new file mode 100644 index 00000000000..bbe4a415b5e --- /dev/null +++ b/src/test/ui/unsafe/unsafe-fn-assign-deref-ptr.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/unsafe-fn-assign-deref-ptr.rs:5:5 + | +LL | *p = 0; + | ^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr b/src/test/ui/unsafe/unsafe-fn-deref-ptr.mir.stderr index 98cb7b876f8..a2614992445 100644 --- a/src/test/ui/unsafe/unsafe-fn-deref-ptr.stderr +++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/unsafe-fn-deref-ptr.rs:2:12 + --> $DIR/unsafe-fn-deref-ptr.rs:5:12 | LL | return *p; | ^^ dereference of raw pointer diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs b/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs index 46445aa261d..dc989535bd6 100644 --- a/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs +++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + fn f(p: *const u8) -> u8 { return *p; //~ ERROR dereference of raw pointer is unsafe } diff --git a/src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr b/src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr new file mode 100644 index 00000000000..a2614992445 --- /dev/null +++ b/src/test/ui/unsafe/unsafe-fn-deref-ptr.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/unsafe-fn-deref-ptr.rs:5:12 + | +LL | return *p; + | ^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.mir.stderr index 410d8d3fb40..99808495ea6 100644 --- a/src/test/ui/unsafe/unsafe-unstable-const-fn.stderr +++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.mir.stderr @@ -1,5 +1,5 @@ error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block - --> $DIR/unsafe-unstable-const-fn.rs:8:5 + --> $DIR/unsafe-unstable-const-fn.rs:11:5 | LL | *a == b | ^^ dereference of raw pointer diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs index c7120e05007..0476759ca6d 100644 --- a/src/test/ui/unsafe/unsafe-unstable-const-fn.rs +++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.rs @@ -1,3 +1,6 @@ +// revisions: mir thir +// [thir]compile-flags: -Z thir-unsafeck + #![stable(feature = "foo", since = "1.33.0")] #![feature(staged_api)] #![feature(const_raw_ptr_deref)] diff --git a/src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr b/src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr new file mode 100644 index 00000000000..99808495ea6 --- /dev/null +++ b/src/test/ui/unsafe/unsafe-unstable-const-fn.thir.stderr @@ -0,0 +1,11 @@ +error[E0133]: dereference of raw pointer is unsafe and requires unsafe function or block + --> $DIR/unsafe-unstable-const-fn.rs:11:5 + | +LL | *a == b + | ^^ dereference of raw pointer + | + = note: raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0133`. diff --git a/src/test/ui/wf/wf-static-method.nll.stderr b/src/test/ui/wf/wf-static-method.nll.stderr index d031a68a51d..9c066a7bdb0 100644 --- a/src/test/ui/wf/wf-static-method.nll.stderr +++ b/src/test/ui/wf/wf-static-method.nll.stderr @@ -68,7 +68,7 @@ LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { | -- -- lifetime `'b` defined here | | | lifetime `'a` defined here -LL | <Evil>::inherent_evil(b) // bug? shouldn't this be an error +LL | <Evil>::inherent_evil(b) | ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'b` must outlive `'a` | = help: consider adding the following bound: `'b: 'a` diff --git a/src/test/ui/wf/wf-static-method.rs b/src/test/ui/wf/wf-static-method.rs index e5a1092175d..6e805d61265 100644 --- a/src/test/ui/wf/wf-static-method.rs +++ b/src/test/ui/wf/wf-static-method.rs @@ -47,7 +47,8 @@ fn indirect_evil<'a, 'b>(b: &'b u32) -> &'a u32 { } fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { - <Evil>::inherent_evil(b) // bug? shouldn't this be an error + <Evil>::inherent_evil(b) + //~^ ERROR cannot infer an appropriate lifetime } diff --git a/src/test/ui/wf/wf-static-method.stderr b/src/test/ui/wf/wf-static-method.stderr index 0c98a809025..c02a8fe4aaf 100644 --- a/src/test/ui/wf/wf-static-method.stderr +++ b/src/test/ui/wf/wf-static-method.stderr @@ -103,7 +103,34 @@ note: ...so that reference does not outlive borrowed content LL | <IndirectEvil>::static_evil(b) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'b` due to conflicting requirements + --> $DIR/wf-static-method.rs:50:5 + | +LL | <Evil>::inherent_evil(b) + | ^^^^^^^^^^^^^^^^^^^^^ + | +note: first, the lifetime cannot outlive the lifetime `'b` as defined on the function body at 49:22... + --> $DIR/wf-static-method.rs:49:22 + | +LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { + | ^^ +note: ...so that reference does not outlive borrowed content + --> $DIR/wf-static-method.rs:50:27 + | +LL | <Evil>::inherent_evil(b) + | ^ +note: but, the lifetime must be valid for the lifetime `'a` as defined on the function body at 49:18... + --> $DIR/wf-static-method.rs:49:18 + | +LL | fn inherent_evil<'a, 'b>(b: &'b u32) -> &'a u32 { + | ^^ +note: ...so that reference does not outlive borrowed content + --> $DIR/wf-static-method.rs:50:5 + | +LL | <Evil>::inherent_evil(b) + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 6 previous errors Some errors have detailed explanations: E0312, E0478, E0495. For more information about an error, try `rustc --explain E0312`. diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 070e459c2d8b79c5b2ac5218064e7603329c92a +Subproject 0cecbd67323ca14a7eb6505900d0d7307b00355 diff --git a/src/tools/clippy/.cargo/config b/src/tools/clippy/.cargo/config index 9b5add4df1c..e95ea224cb6 100644 --- a/src/tools/clippy/.cargo/config +++ b/src/tools/clippy/.cargo/config @@ -2,6 +2,7 @@ uitest = "test --test compile-test" dev = "run --target-dir clippy_dev/target --package clippy_dev --bin clippy_dev --manifest-path clippy_dev/Cargo.toml --" lintcheck = "run --target-dir lintcheck/target --package lintcheck --bin lintcheck --manifest-path lintcheck/Cargo.toml -- " +collect-metadata = "test --test dogfood --features metadata-collector-lint -- run_metadata_collection_lint --ignored" [build] rustflags = ["-Zunstable-options"] diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index ae6f1aa1b30..f27fee87dc1 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -90,6 +90,11 @@ jobs: - name: Checkout uses: actions/checkout@v2.3.3 + # FIXME: should not be necessary once 1.24.2 is the default version on the windows runner + - name: Update rustup + run: rustup self update + if: runner.os == 'Windows' + - name: Install toolchain run: rustup show active-toolchain diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 204d56e2a98..41af8e190dd 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,11 +6,195 @@ document. ## Unreleased / In Rust Nightly -[6ed6f1e...master](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...master) +[7c7683c...master](https://github.com/rust-lang/rust-clippy/compare/7c7683c...master) + +## Rust 1.53 + +Current beta, release 2021-06-17 + +[6ed6f1e...7c7683c](https://github.com/rust-lang/rust-clippy/compare/6ed6f1e...7c7683c) + +### New Lints + +* [`option_filter_map`] + [#6342](https://github.com/rust-lang/rust-clippy/pull/6342) +* [`branches_sharing_code`] + [#6463](https://github.com/rust-lang/rust-clippy/pull/6463) +* [`needless_for_each`] + [#6706](https://github.com/rust-lang/rust-clippy/pull/6706) +* [`if_then_some_else_none`] + [#6859](https://github.com/rust-lang/rust-clippy/pull/6859) +* [`non_octal_unix_permissions`] + [#7001](https://github.com/rust-lang/rust-clippy/pull/7001) +* [`unnecessary_self_imports`] + [#7072](https://github.com/rust-lang/rust-clippy/pull/7072) +* [`bool_assert_comparison`] + [#7083](https://github.com/rust-lang/rust-clippy/pull/7083) +* [`cloned_instead_of_copied`] + [#7098](https://github.com/rust-lang/rust-clippy/pull/7098) +* [`flat_map_option`] + [#7101](https://github.com/rust-lang/rust-clippy/pull/7101) + +### Moves and Deprecations + +* Deprecate [`filter_map`] lint + [#7059](https://github.com/rust-lang/rust-clippy/pull/7059) +* Move [`transmute_ptr_to_ptr`] to `pedantic` + [#7102](https://github.com/rust-lang/rust-clippy/pull/7102) + +### Enhancements + +* [`mem_replace_with_default`]: Also lint on common std constructors + [#6820](https://github.com/rust-lang/rust-clippy/pull/6820) +* [`wrong_self_convention`]: Also lint on `to_*_mut` methods + [#6828](https://github.com/rust-lang/rust-clippy/pull/6828) +* [`wildcard_enum_match_arm`], [`match_wildcard_for_single_variants`]: + [#6863](https://github.com/rust-lang/rust-clippy/pull/6863) + * Attempt to find a common path prefix in suggestion + * Don't lint on `Option` and `Result` + * Consider `Self` prefix +* [`explicit_deref_methods`]: Also lint on chained `deref` calls + [#6865](https://github.com/rust-lang/rust-clippy/pull/6865) +* [`or_fun_call`]: Also lint on `unsafe` blocks + [#6928](https://github.com/rust-lang/rust-clippy/pull/6928) +* [`vec_box`], [`linkedlist`], [`option_option`]: Also lint in `const` and + `static` items [#6938](https://github.com/rust-lang/rust-clippy/pull/6938) +* [`search_is_some`]: Also check for `is_none` + [#6942](https://github.com/rust-lang/rust-clippy/pull/6942) +* [`string_lit_as_bytes`]: Also lint on `into_bytes` + [#6959](https://github.com/rust-lang/rust-clippy/pull/6959) +* [`len_without_is_empty`]: Also lint if function signatures of `len` and + `is_empty` don't match + [#6980](https://github.com/rust-lang/rust-clippy/pull/6980) +* [`redundant_pattern_matching`]: Also lint if the pattern is a `&` pattern + [#6991](https://github.com/rust-lang/rust-clippy/pull/6991) +* [`clone_on_copy`]: Also lint on chained method calls taking `self` by value + [#7000](https://github.com/rust-lang/rust-clippy/pull/7000) +* [`missing_panics_doc`]: Also lint on `assert_eq!` and `assert_ne!` + [#7029](https://github.com/rust-lang/rust-clippy/pull/7029) +* [`needless_return`]: Also lint in `async` functions + [#7067](https://github.com/rust-lang/rust-clippy/pull/7067) +* [`unused_io_amount`]: Also lint on expressions like `_.read().ok()?` + [#7100](https://github.com/rust-lang/rust-clippy/pull/7100) +* [`iter_cloned_collect`]: Also lint on large arrays, since const-generics are + now stable [#7138](https://github.com/rust-lang/rust-clippy/pull/7138) + +### False Positive Fixes + +* [`upper_case_acronyms`]: No longer lints on public items + [#6805](https://github.com/rust-lang/rust-clippy/pull/6805) +* [`suspicious_map`]: No longer lints when side effects may occur inside the + `map` call [#6831](https://github.com/rust-lang/rust-clippy/pull/6831) +* [`manual_map`], [`manual_unwrap_or`]: No longer lints in `const` functions + [#6917](https://github.com/rust-lang/rust-clippy/pull/6917) +* [`wrong_self_convention`]: Now respects `Copy` types + [#6924](https://github.com/rust-lang/rust-clippy/pull/6924) +* [`needless_question_mark`]: No longer lints if the `?` and the `Some(..)` come + from different macro contexts [#6935](https://github.com/rust-lang/rust-clippy/pull/6935) +* [`map_entry`]: Better detect if the entry API can be used + [#6937](https://github.com/rust-lang/rust-clippy/pull/6937) +* [`or_fun_call`]: No longer lints on some `len` function calls + [#6950](https://github.com/rust-lang/rust-clippy/pull/6950) +* [`new_ret_no_self`]: No longer lints when `Self` is returned with different + generic arguments [#6952](https://github.com/rust-lang/rust-clippy/pull/6952) +* [`upper_case_acronyms`]: No longer lints on public items + [#6981](https://github.com/rust-lang/rust-clippy/pull/6981) +* [`explicit_into_iter_loop`]: Only lint when `into_iter` is an implementation + of `IntoIterator` [#6982](https://github.com/rust-lang/rust-clippy/pull/6982) +* [`expl_impl_clone_on_copy`]: Take generic constraints into account before + suggesting to use `derive` instead + [#6993](https://github.com/rust-lang/rust-clippy/pull/6993) +* [`missing_panics_doc`]: No longer lints when only debug-assertions are used + [#6996](https://github.com/rust-lang/rust-clippy/pull/6996) +* [`clone_on_copy`]: Only lint when using the `Clone` trait + [#7000](https://github.com/rust-lang/rust-clippy/pull/7000) +* [`wrong_self_convention`]: No longer lints inside a trait implementation + [#7002](https://github.com/rust-lang/rust-clippy/pull/7002) +* [`redundant_clone`]: No longer lints when the cloned value is modified while + the clone is in use + [#7011](https://github.com/rust-lang/rust-clippy/pull/7011) +* [`same_item_push`]: No longer lints if the `Vec` is used in the loop body + [#7018](https://github.com/rust-lang/rust-clippy/pull/7018) +* [`cargo_common_metadata`]: Remove author requirement + [#7026](https://github.com/rust-lang/rust-clippy/pull/7026) +* [`panic_in_result_fn`]: No longer lints on `debug_assert` family + [#7060](https://github.com/rust-lang/rust-clippy/pull/7060) +* [`panic`]: No longer wrongfully lints on `debug_assert` with message + [#7063](https://github.com/rust-lang/rust-clippy/pull/7063) +* [`wrong_self_convention`]: No longer lints in trait implementations where no + `self` is involved [#7064](https://github.com/rust-lang/rust-clippy/pull/7064) +* [`missing_const_for_fn`]: No longer lints when unstable `const` function is + involved [#7076](https://github.com/rust-lang/rust-clippy/pull/7076) +* [`suspicious_else_formatting`]: Allow Allman style braces + [#7087](https://github.com/rust-lang/rust-clippy/pull/7087) +* [`inconsistent_struct_constructor`]: No longer lints in macros + [#7097](https://github.com/rust-lang/rust-clippy/pull/7097) +* [`single_component_path_imports`]: No longer lints on macro re-exports + [#7120](https://github.com/rust-lang/rust-clippy/pull/7120) + +### Suggestion Fixes/Improvements + +* [`redundant_pattern_matching`]: Add a note when applying this lint would + change the drop order + [#6568](https://github.com/rust-lang/rust-clippy/pull/6568) +* [`write_literal`], [`print_literal`]: Add auto-applicable suggestion + [#6821](https://github.com/rust-lang/rust-clippy/pull/6821) +* [`manual_map`]: Fix suggestion for complex `if let ... else` chains + [#6856](https://github.com/rust-lang/rust-clippy/pull/6856) +* [`inconsistent_struct_constructor`]: Make lint description and message clearer + [#6892](https://github.com/rust-lang/rust-clippy/pull/6892) +* [`map_entry`]: Now suggests `or_insert`, `insert_with` or `match _.entry(_)` + as appropriate [#6937](https://github.com/rust-lang/rust-clippy/pull/6937) +* [`manual_flatten`]: Suggest to insert `copied` if necessary + [#6962](https://github.com/rust-lang/rust-clippy/pull/6962) +* [`redundant_slicing`]: Fix suggestion when a re-borrow might be required or + when the value is from a macro call + [#6975](https://github.com/rust-lang/rust-clippy/pull/6975) +* [`match_wildcard_for_single_variants`]: Fix suggestion for hidden variant + [#6988](https://github.com/rust-lang/rust-clippy/pull/6988) +* [`clone_on_copy`]: Correct suggestion when the cloned value is a macro call + [#7000](https://github.com/rust-lang/rust-clippy/pull/7000) +* [`manual_map`]: Fix suggestion at the end of an if chain + [#7004](https://github.com/rust-lang/rust-clippy/pull/7004) +* Fix needless parenthesis output in multiple lint suggestions + [#7013](https://github.com/rust-lang/rust-clippy/pull/7013) +* [`needless_collect`]: Better explanation in the lint message + [#7020](https://github.com/rust-lang/rust-clippy/pull/7020) +* [`useless_vec`]: Now considers mutability + [#7036](https://github.com/rust-lang/rust-clippy/pull/7036) +* [`useless_format`]: Wrap the content in braces if necessary + [#7092](https://github.com/rust-lang/rust-clippy/pull/7092) +* [`single_match`]: Don't suggest an equality check for types which don't + implement `PartialEq` + [#7093](https://github.com/rust-lang/rust-clippy/pull/7093) +* [`from_over_into`]: Mention type in help message + [#7099](https://github.com/rust-lang/rust-clippy/pull/7099) +* [`manual_unwrap_or`]: Fix invalid code suggestion due to a macro call + [#7136](https://github.com/rust-lang/rust-clippy/pull/7136) + +### ICE Fixes + +* [`macro_use_imports`] + [#7022](https://github.com/rust-lang/rust-clippy/pull/7022) +* [`missing_panics_doc`] + [#7034](https://github.com/rust-lang/rust-clippy/pull/7034) +* [`tabs_in_doc_comments`] + [#7039](https://github.com/rust-lang/rust-clippy/pull/7039) +* [`missing_const_for_fn`] + [#7128](https://github.com/rust-lang/rust-clippy/pull/7128) + +### Others + +* [Clippy's lint + list](https://rust-lang.github.io/rust-clippy/master/index.html) now supports + themes [#7030](https://github.com/rust-lang/rust-clippy/pull/7030) +* Lints that were uplifted to `rustc` now mention the new `rustc` name in the + deprecation warning + [#7056](https://github.com/rust-lang/rust-clippy/pull/7056) ## Rust 1.52 -Current beta, release 2021-05-06 +Current stable, released 2021-05-06 [3e41797...6ed6f1e](https://github.com/rust-lang/rust-clippy/compare/3e41797...6ed6f1e) @@ -99,7 +283,7 @@ Current beta, release 2021-05-06 [#6682](https://github.com/rust-lang/rust-clippy/pull/6682) * [`unit_arg`]: No longer lints on unit arguments when they come from a path expression. [#6601](https://github.com/rust-lang/rust-clippy/pull/6601) -* [`cargo_common_metadata`]: No longer lints if +* [`cargo_common_metadata`]: No longer lints if [`publish = false`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field) is defined in the manifest [#6650](https://github.com/rust-lang/rust-clippy/pull/6650) @@ -124,11 +308,11 @@ Current beta, release 2021-05-06 * [`useless_format`]: Improved the documentation example [#6854](https://github.com/rust-lang/rust-clippy/pull/6854) -* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper +* Clippy's [`README.md`]: Includes a new subsection on running Clippy as a rustc wrapper [#6782](https://github.com/rust-lang/rust-clippy/pull/6782) ### Others -* Running `cargo clippy` after `cargo check` now works as expected +* Running `cargo clippy` after `cargo check` now works as expected (`cargo clippy` and `cargo check` no longer shares the same build cache) [#6687](https://github.com/rust-lang/rust-clippy/pull/6687) * Cargo now re-runs Clippy if arguments after `--` provided to `cargo clippy` are changed. @@ -145,7 +329,7 @@ Current beta, release 2021-05-06 ## Rust 1.51 -Current stable, released 2021-03-25 +Released 2021-03-25 [4911ab1...3e41797](https://github.com/rust-lang/rust-clippy/compare/4911ab1...3e41797) @@ -2309,6 +2493,7 @@ Released 2018-09-13 [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains [`manual_saturating_arithmetic`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_saturating_arithmetic +[`manual_str_repeat`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_str_repeat [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or @@ -2365,6 +2550,7 @@ Released 2018-09-13 [`mutex_integer`]: https://rust-lang.github.io/rust-clippy/master/index.html#mutex_integer [`naive_bytecount`]: https://rust-lang.github.io/rust-clippy/master/index.html#naive_bytecount [`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type +[`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool [`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference @@ -2437,6 +2623,7 @@ Released 2018-09-13 [`redundant_pub_crate`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate [`redundant_slicing`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_slicing [`redundant_static_lifetimes`]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_static_lifetimes +[`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro @@ -2485,6 +2672,7 @@ Released 2018-09-13 [`suspicious_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_map [`suspicious_op_assign_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_op_assign_impl [`suspicious_operation_groupings`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_operation_groupings +[`suspicious_splitn`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_splitn [`suspicious_unary_op_formatting`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_unary_op_formatting [`tabs_in_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#tabs_in_doc_comments [`temporary_assignment`]: https://rust-lang.github.io/rust-clippy/master/index.html#temporary_assignment @@ -2538,6 +2726,7 @@ Released 2018-09-13 [`unsound_collection_transmute`]: https://rust-lang.github.io/rust-clippy/master/index.html#unsound_collection_transmute [`unstable_as_mut_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_mut_slice [`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice +[`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async [`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect [`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount [`unused_self`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_self diff --git a/src/tools/clippy/COPYRIGHT b/src/tools/clippy/COPYRIGHT index 80d64472c70..238c919b69d 100644 --- a/src/tools/clippy/COPYRIGHT +++ b/src/tools/clippy/COPYRIGHT @@ -1,4 +1,4 @@ -Copyright 2014-2020 The Rust Project Developers +Copyright 2014-2021 The Rust Project Developers Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index f010e609604..b003b15a11d 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -33,12 +33,13 @@ tempfile = { version = "3.1.0", optional = true } cargo_metadata = "0.12" compiletest_rs = { version = "0.6.0", features = ["tmp"] } tester = "0.9" -clippy-mini-macro-test = { version = "0.2", path = "mini-macro" } serde = { version = "1.0", features = ["derive"] } derive-new = "0.5" regex = "1.4" quote = "1" syn = { version = "1", features = ["full"] } +# This is used by the `collect-metadata` alias. +filetime = "0.2" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` @@ -49,7 +50,7 @@ rustc-workspace-hack = "1.0.0" rustc_tools_util = { version = "0.2.0", path = "rustc_tools_util" } [features] -deny-warnings = [] +deny-warnings = ["clippy_lints/deny-warnings"] integration = ["tempfile"] internal-lints = ["clippy_lints/internal-lints"] metadata-collector-lint = ["internal-lints", "clippy_lints/metadata-collector-lint"] diff --git a/src/tools/clippy/LICENSE-APACHE b/src/tools/clippy/LICENSE-APACHE index d821a4de2be..04169a42b8b 100644 --- a/src/tools/clippy/LICENSE-APACHE +++ b/src/tools/clippy/LICENSE-APACHE @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work. same "printed page" as the copyright notice for easier identification within third-party archives. -Copyright 2014-2020 The Rust Project Developers +Copyright 2014-2021 The Rust Project Developers Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/src/tools/clippy/LICENSE-MIT b/src/tools/clippy/LICENSE-MIT index b7c70dd4026..90a2d3950d1 100644 --- a/src/tools/clippy/LICENSE-MIT +++ b/src/tools/clippy/LICENSE-MIT @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2014-2020 The Rust Project Developers +Copyright (c) 2014-2021 The Rust Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index 8c0c16c443d..6c556f579ca 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -147,6 +147,7 @@ Some lints can be configured in a TOML file named `clippy.toml` or `.clippy.toml value` mapping eg. ```toml +avoid-breaking-exported-api = false blacklisted-names = ["toto", "tata", "titi"] cognitive-complexity-threshold = 30 ``` @@ -236,7 +237,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT ## License -Copyright 2014-2020 The Rust Project Developers +Copyright 2014-2021 The Rust Project Developers Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license diff --git a/src/tools/clippy/build.rs b/src/tools/clippy/build.rs index 018375dbada..b5484bec3c8 100644 --- a/src/tools/clippy/build.rs +++ b/src/tools/clippy/build.rs @@ -14,6 +14,6 @@ fn main() { ); println!( "cargo:rustc-env=RUSTC_RELEASE_CHANNEL={}", - rustc_tools_util::get_channel().unwrap_or_default() + rustc_tools_util::get_channel() ); } diff --git a/src/tools/clippy/clippy.toml b/src/tools/clippy/clippy.toml new file mode 100644 index 00000000000..cda8d17eed4 --- /dev/null +++ b/src/tools/clippy/clippy.toml @@ -0,0 +1 @@ +avoid-breaking-exported-api = false diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs index 1e5a140e964..69f42aca8b6 100644 --- a/src/tools/clippy/clippy_dev/src/lib.rs +++ b/src/tools/clippy/clippy_dev/src/lib.rs @@ -1,5 +1,7 @@ -#![cfg_attr(feature = "deny-warnings", deny(warnings))] #![feature(once_cell)] +#![cfg_attr(feature = "deny-warnings", deny(warnings))] +// warn on lints, that are included in `rust-lang/rust`s bootstrap +#![warn(rust_2018_idioms, unused_lifetimes)] use itertools::Itertools; use regex::Regex; diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs index f4da783502c..7040c257c83 100644 --- a/src/tools/clippy/clippy_dev/src/main.rs +++ b/src/tools/clippy/clippy_dev/src/main.rs @@ -1,4 +1,6 @@ #![cfg_attr(feature = "deny-warnings", deny(warnings))] +// warn on lints, that are included in `rust-lang/rust`s bootstrap +#![warn(rust_2018_idioms, unused_lifetimes)] use clap::{App, Arg, ArgMatches, SubCommand}; use clippy_dev::{bless, fmt, ide_setup, new_lint, serve, stderr_length_check, update_lints}; diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 7ceb1da6a6e..48f2972ec58 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -30,7 +30,7 @@ rustc-semver = "1.1.0" url = { version = "2.1.0", features = ["serde"] } [features] -deny-warnings = [] +deny-warnings = ["clippy_utils/deny-warnings"] # build clippy with internal lints enabled, off by default internal-lints = ["clippy_utils/internal-lints"] metadata-collector-lint = ["serde_json", "clippy_utils/metadata-collector-lint"] diff --git a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs index 5fbf4bdbd18..49d4350123f 100644 --- a/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/absurd_extreme_comparisons.rs @@ -3,9 +3,8 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use crate::consts::{constant, Constant}; - use clippy_utils::comparisons::{normalize_comparison, Rel}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet; use clippy_utils::ty::is_isize_or_usize; diff --git a/src/tools/clippy/clippy_lints/src/arithmetic.rs b/src/tools/clippy/clippy_lints/src/arithmetic.rs index c560f545d6a..24c2a972811 100644 --- a/src/tools/clippy/clippy_lints/src/arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/arithmetic.rs @@ -1,4 +1,4 @@ -use crate::consts::constant_simple; +use clippy_utils::consts::constant_simple; use clippy_utils::diagnostics::span_lint; use rustc_hir as hir; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs index c565e29d078..5235b2642d1 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use clippy_utils::source::snippet_opt; use clippy_utils::{is_direct_expn_of, is_expn_of, match_panic_call}; @@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { &format!("`assert!(false, {})` should probably be replaced", panic_message), None, &format!("use `panic!({})` or `unreachable!({})`", panic_message, panic_message), - ) + ); }; if let Some(debug_assert_span) = is_expn_of(e.span, "debug_assert") { diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index c5b01461c1c..932cd58bf62 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -273,7 +273,7 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { let attrs = cx.tcx.hir().attrs(item.hir_id()); if is_relevant_item(cx, item) { - check_attrs(cx, item.span, item.ident.name, attrs) + check_attrs(cx, item.span, item.ident.name, attrs); } match item.kind { ItemKind::ExternCrate(..) | ItemKind::Use(..) => { @@ -343,13 +343,13 @@ impl<'tcx> LateLintPass<'tcx> for Attributes { fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx ImplItem<'_>) { if is_relevant_impl(cx, item) { - check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())) + check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())); } } fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx TraitItem<'_>) { if is_relevant_trait(cx, item) { - check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())) + check_attrs(cx, item.span, item.ident.name, cx.tcx.hir().attrs(item.hir_id())); } } } diff --git a/src/tools/clippy/clippy_lints/src/bit_mask.rs b/src/tools/clippy/clippy_lints/src/bit_mask.rs index f7daf3dab49..991ed94572c 100644 --- a/src/tools/clippy/clippy_lints/src/bit_mask.rs +++ b/src/tools/clippy/clippy_lints/src/bit_mask.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_then}; use clippy_utils::sugg::Sugg; use if_chain::if_chain; @@ -115,9 +115,9 @@ impl<'tcx> LateLintPass<'tcx> for BitMask { if let ExprKind::Binary(cmp, left, right) = &e.kind { if cmp.node.is_comparison() { if let Some(cmp_opt) = fetch_int_literal(cx, right) { - check_compare(cx, left, cmp.node, cmp_opt, e.span) + check_compare(cx, left, cmp.node, cmp_opt, e.span); } else if let Some(cmp_val) = fetch_int_literal(cx, left) { - check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span) + check_compare(cx, right, invert_cmp(cmp.node), cmp_val, e.span); } } } @@ -171,7 +171,7 @@ fn check_compare(cx: &LateContext<'_>, bit_op: &Expr<'_>, cmp_op: BinOpKind, cmp } fetch_int_literal(cx, right) .or_else(|| fetch_int_literal(cx, left)) - .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span)) + .map_or((), |mask| check_bit_mask(cx, op.node, cmp_op, mask, cmp_value, span)); } } diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs index 67f0e0c7870..e72399af232 100644 --- a/src/tools/clippy/clippy_lints/src/booleans.rs +++ b/src/tools/clippy/clippy_lints/src/booleans.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool { _: Span, _: HirId, ) { - NonminimalBoolVisitor { cx }.visit_body(body) + NonminimalBoolVisitor { cx }.visit_body(body); } } @@ -184,7 +184,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> { Term(n) => { let terminal = self.terminals[n as usize]; if let Some(str) = simplify_not(self.cx, terminal) { - self.output.push_str(&str) + self.output.push_str(&str); } else { self.output.push('!'); let snip = snippet_opt(self.cx, terminal.span)?; @@ -452,7 +452,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> { } match &e.kind { ExprKind::Binary(binop, _, _) if binop.node == BinOpKind::Or || binop.node == BinOpKind::And => { - self.bool_expr(e) + self.bool_expr(e); }, ExprKind::Unary(UnOp::Not, inner) => { if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() { diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs index 040e0ca8864..c9c111a2847 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{method_chain_args, sext}; use if_chain::if_chain; diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs index dae5c86bd44..6e950738239 100644 --- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs +++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs @@ -92,7 +92,7 @@ declare_lint_pass!(CollapsibleIf => [COLLAPSIBLE_IF, COLLAPSIBLE_ELSE_IF]); impl EarlyLintPass for CollapsibleIf { fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &ast::Expr) { if !expr.span.from_expansion() { - check_if(cx, expr) + check_if(cx, expr); } } } diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs index 2a61d58e653..b6999bef6e7 100644 --- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs +++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs @@ -120,7 +120,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain { "`if` chain can be rewritten with `match`", None, "consider rewriting the `if` chain to use `cmp` and `match`", - ) + ); } } diff --git a/src/tools/clippy/clippy_lints/src/consts.rs b/src/tools/clippy/clippy_lints/src/consts.rs deleted file mode 100644 index 7e87f53e3fb..00000000000 --- a/src/tools/clippy/clippy_lints/src/consts.rs +++ /dev/null @@ -1 +0,0 @@ -pub use clippy_utils::consts::*; diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index f956d171bfb..376a14b8181 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -476,7 +476,7 @@ fn emit_branches_sharing_code_lint( } suggestions.push(("end", span, suggestion.to_string())); - add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit() + add_expr_note = !cx.typeck_results().expr_ty(if_expr).is_unit(); } let add_optional_msgs = |diag: &mut DiagnosticBuilder<'_>| { diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs index 6e883942680..759f7d4062d 100644 --- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs +++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs @@ -181,9 +181,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> { match stmt.kind { StmtKind::Local(local) => { if local.ty.is_some() { - self.ty_bounds.push(TyBound::Any) + self.ty_bounds.push(TyBound::Any); } else { - self.ty_bounds.push(TyBound::Nothing) + self.ty_bounds.push(TyBound::Nothing); } }, diff --git a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs index 4688b3d5105..04f3d77464f 100644 --- a/src/tools/clippy/clippy_lints/src/deprecated_lints.rs +++ b/src/tools/clippy/clippy_lints/src/deprecated_lints.rs @@ -1,6 +1,13 @@ +/// This struct fakes the `Lint` declaration that is usually created by `declare_lint!`. This +/// enables the simple extraction of the metadata without changing the current deprecation +/// declaration. +pub struct ClippyDeprecatedLint; + macro_rules! declare_deprecated_lint { - (pub $name: ident, $_reason: expr) => { - declare_lint!(pub $name, Allow, "deprecated lint") + { $(#[$attr:meta])* pub $name: ident, $_reason: expr} => { + $(#[$attr])* + #[allow(dead_code)] + pub static $name: ClippyDeprecatedLint = ClippyDeprecatedLint {}; } } @@ -134,3 +141,22 @@ declare_deprecated_lint! { pub FILTER_MAP, "this lint has been replaced by `manual_filter_map`, a more specific lint" } + +declare_deprecated_lint! { + /// **What it does:** Nothing. This lint has been deprecated. + /// + /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which + /// enables the `enum_variant_names` lint for public items. + /// ``` + pub PUB_ENUM_VARIANT_NAMES, + "set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items" +} + +declare_deprecated_lint! { + /// **What it does:** Nothing. This lint has been deprecated. + /// + /// **Deprecation reason:** The `avoid_breaking_exported_api` config option was added, which + /// enables the `wrong_self_conversion` lint for public items. + pub WRONG_PUB_SELF_CONVENTION, + "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items" +} diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index e742cd626ab..840c1eba79d 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -12,7 +12,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::map::Map; use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::{source_map::Span}; +use rustc_span::source_map::Span; declare_clippy_lint! { /// **What it does:** Checks for deriving `Hash` but implementing `PartialEq` @@ -310,15 +310,11 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &T // there's a Copy impl for any instance of the adt. if !is_copy(cx, ty) { if ty_subs.non_erasable_generics().next().is_some() { - let has_copy_impl = cx - .tcx - .all_local_trait_impls(()) - .get(©_id) - .map_or(false, |impls| { - impls - .iter() - .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did == adt.did)) - }); + let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(©_id).map_or(false, |impls| { + impls + .iter() + .any(|&id| matches!(cx.tcx.type_of(id).kind(), ty::Adt(adt, _) if ty_adt.did == adt.did)) + }); if !has_copy_impl { return; } diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index fb53b55ebd6..e67ec4e06c5 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -383,7 +383,7 @@ pub fn strip_doc_comment_decoration(doc: &str, comment_kind: CommentKind, span: let mut no_stars = String::with_capacity(doc.len()); for line in doc.lines() { let mut chars = line.chars(); - while let Some(c) = chars.next() { + for c in &mut chars { if c.is_whitespace() { no_stars.push(c); } else { diff --git a/src/tools/clippy/clippy_lints/src/double_comparison.rs b/src/tools/clippy/clippy_lints/src/double_comparison.rs index 58543ae6e4e..4966638cb1b 100644 --- a/src/tools/clippy/clippy_lints/src/double_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/double_comparison.rs @@ -70,16 +70,16 @@ impl<'tcx> DoubleComparisons { #[rustfmt::skip] match (op, lkind, rkind) { (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Lt) | (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Eq) => { - lint_double_comparison!(<=) + lint_double_comparison!(<=); }, (BinOpKind::Or, BinOpKind::Eq, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Eq) => { - lint_double_comparison!(>=) + lint_double_comparison!(>=); }, (BinOpKind::Or, BinOpKind::Lt, BinOpKind::Gt) | (BinOpKind::Or, BinOpKind::Gt, BinOpKind::Lt) => { - lint_double_comparison!(!=) + lint_double_comparison!(!=); }, (BinOpKind::And, BinOpKind::Le, BinOpKind::Ge) | (BinOpKind::And, BinOpKind::Ge, BinOpKind::Le) => { - lint_double_comparison!(==) + lint_double_comparison!(==); }, _ => (), }; diff --git a/src/tools/clippy/clippy_lints/src/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/duration_subsec.rs index 529807770f3..94b09bf7173 100644 --- a/src/tools/clippy/clippy_lints/src/duration_subsec.rs +++ b/src/tools/clippy/clippy_lints/src/duration_subsec.rs @@ -7,7 +7,7 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Spanned; -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::paths; diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 8db5050a5ac..2eb8b1422ed 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -469,7 +469,7 @@ impl<'tcx> Visitor<'tcx> for InsertSearcher<'_, 'tcx> { let mut is_map_used = self.is_map_used; for arm in arms { if let Some(Guard::If(guard) | Guard::IfLet(_, guard)) = arm.guard { - self.visit_non_tail_expr(guard) + self.visit_non_tail_expr(guard); } is_map_used |= self.visit_cond_arm(arm.body); } diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs index 7a98ae39d3a..021136ac5e0 100644 --- a/src/tools/clippy/clippy_lints/src/enum_clike.rs +++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs @@ -1,7 +1,7 @@ //! lint on C-like enums that are `repr(isize/usize)` and have values that //! don't fit into an `i32` -use crate::consts::{miri_to_const, Constant}; +use clippy_utils::consts::{miri_to_const, Constant}; use clippy_utils::diagnostics::span_lint; use rustc_hir::{Item, ItemKind}; use rustc_lint::{LateContext, LateLintPass}; diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs index 0ecc0bc3eb6..b1a105a51c1 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs @@ -3,8 +3,8 @@ use clippy_utils::camel_case; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::source::is_present_in_source; -use rustc_ast::ast::{EnumDef, Item, ItemKind, VisibilityKind}; -use rustc_lint::{EarlyContext, EarlyLintPass, Lint}; +use rustc_hir::{EnumDef, Item, ItemKind}; +use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; @@ -40,36 +40,6 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** Detects public enumeration variants that are - /// prefixed or suffixed by the same characters. - /// - /// **Why is this bad?** Public enumeration variant names should specify their variant, - /// not repeat the enumeration name. - /// - /// **Known problems:** None. - /// - /// **Example:** - /// ```rust - /// pub enum Cake { - /// BlackForestCake, - /// HummingbirdCake, - /// BattenbergCake, - /// } - /// ``` - /// Could be written as: - /// ```rust - /// pub enum Cake { - /// BlackForest, - /// Hummingbird, - /// Battenberg, - /// } - /// ``` - pub PUB_ENUM_VARIANT_NAMES, - pedantic, - "public enums where all variants share a prefix/postfix" -} - -declare_clippy_lint! { /// **What it does:** Detects type names that are prefixed or suffixed by the /// containing module's name. /// @@ -127,21 +97,22 @@ declare_clippy_lint! { pub struct EnumVariantNames { modules: Vec<(Symbol, String)>, threshold: u64, + avoid_breaking_exported_api: bool, } impl EnumVariantNames { #[must_use] - pub fn new(threshold: u64) -> Self { + pub fn new(threshold: u64, avoid_breaking_exported_api: bool) -> Self { Self { modules: Vec::new(), threshold, + avoid_breaking_exported_api, } } } impl_lint_pass!(EnumVariantNames => [ ENUM_VARIANT_NAMES, - PUB_ENUM_VARIANT_NAMES, MODULE_NAME_REPETITIONS, MODULE_INCEPTION ]); @@ -167,33 +138,42 @@ fn partial_rmatch(post: &str, name: &str) -> usize { } fn check_variant( - cx: &EarlyContext<'_>, + cx: &LateContext<'_>, threshold: u64, - def: &EnumDef, + def: &EnumDef<'_>, item_name: &str, item_name_chars: usize, span: Span, - lint: &'static Lint, ) { if (def.variants.len() as u64) < threshold { return; } - for var in &def.variants { + for var in def.variants { let name = var.ident.name.as_str(); if partial_match(item_name, &name) == item_name_chars && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) { - span_lint(cx, lint, var.span, "variant name starts with the enum's name"); + span_lint( + cx, + ENUM_VARIANT_NAMES, + var.span, + "variant name starts with the enum's name", + ); } if partial_rmatch(item_name, &name) == item_name_chars { - span_lint(cx, lint, var.span, "variant name ends with the enum's name"); + span_lint( + cx, + ENUM_VARIANT_NAMES, + var.span, + "variant name ends with the enum's name", + ); } } let first = &def.variants[0].ident.name.as_str(); let mut pre = &first[..camel_case::until(&*first)]; let mut post = &first[camel_case::from(&*first)..]; - for var in &def.variants { + for var in def.variants { let name = var.ident.name.as_str(); let pre_match = partial_match(pre, &name); @@ -226,7 +206,7 @@ fn check_variant( }; span_lint_and_help( cx, - lint, + ENUM_VARIANT_NAMES, span, &format!("all variants have the same {}fix: `{}`", what, value), None, @@ -261,14 +241,14 @@ fn to_camel_case(item_name: &str) -> String { s } -impl EarlyLintPass for EnumVariantNames { - fn check_item_post(&mut self, _cx: &EarlyContext<'_>, _item: &Item) { +impl LateLintPass<'_> for EnumVariantNames { + fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) { let last = self.modules.pop(); assert!(last.is_some()); } #[allow(clippy::similar_names)] - fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) { + fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { let item_name = item.ident.name.as_str(); let item_name_chars = item_name.chars().count(); let item_camel = to_camel_case(&item_name); @@ -286,7 +266,7 @@ impl EarlyLintPass for EnumVariantNames { ); } } - if item.vis.kind.is_pub() { + if item.vis.node.is_pub() { let matching = partial_match(mod_camel, &item_camel); let rmatching = partial_rmatch(mod_camel, &item_camel); let nchars = mod_camel.chars().count(); @@ -317,11 +297,9 @@ impl EarlyLintPass for EnumVariantNames { } } if let ItemKind::Enum(ref def, _) = item.kind { - let lint = match item.vis.kind { - VisibilityKind::Public => PUB_ENUM_VARIANT_NAMES, - _ => ENUM_VARIANT_NAMES, - }; - check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span, lint); + if !(self.avoid_breaking_exported_api && cx.access_levels.is_exported(item.hir_id())) { + check_variant(cx, self.threshold, def, &item_name, item_name_chars, item.span); + } } self.modules.push((item.ident.name, item_camel)); } diff --git a/src/tools/clippy/clippy_lints/src/eq_op.rs b/src/tools/clippy/clippy_lints/src/eq_op.rs index 90f391b5f5c..a3a8e748d99 100644 --- a/src/tools/clippy/clippy_lints/src/eq_op.rs +++ b/src/tools/clippy/clippy_lints/src/eq_op.rs @@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { vec![(left.span, lsnip), (right.span, rsnip)], ); }, - ) + ); } else if lcpy && !rcpy && implements_trait(cx, lty, trait_id, &[cx.typeck_results().expr_ty(right).into()]) @@ -175,7 +175,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ) + ); } else if !lcpy && rcpy && implements_trait(cx, cx.typeck_results().expr_ty(left), trait_id, &[rty.into()]) @@ -194,7 +194,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ) + ); } }, // &foo == bar @@ -218,7 +218,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { Applicability::MaybeIncorrect, // FIXME #2597 ); }, - ) + ); } }, // foo == &bar @@ -236,7 +236,7 @@ impl<'tcx> LateLintPass<'tcx> for EqOp { rsnip, Applicability::MaybeIncorrect, // FIXME #2597 ); - }) + }); } }, _ => {}, diff --git a/src/tools/clippy/clippy_lints/src/erasing_op.rs b/src/tools/clippy/clippy_lints/src/erasing_op.rs index f95ca86a2d0..4aa9c25b1b0 100644 --- a/src/tools/clippy/clippy_lints/src/erasing_op.rs +++ b/src/tools/clippy/clippy_lints/src/erasing_op.rs @@ -1,11 +1,10 @@ +use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint; 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::Span; -use crate::consts::{constant_simple, Constant}; - declare_clippy_lint! { /// **What it does:** Checks for erasing operations, e.g., `x * 0`. /// diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs index 2f1aa53236d..8d066f305ee 100644 --- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs +++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs @@ -77,7 +77,7 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction { for arg in args { // skip `foo(macro!())` if arg.span.ctxt() == expr.span.ctxt() { - check_closure(cx, arg) + check_closure(cx, arg); } } }, @@ -92,17 +92,19 @@ fn check_closure(cx: &LateContext<'_>, expr: &Expr<'_>) { let ex = &body.value; if ex.span.ctxt() != expr.span.ctxt() { - if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) { - // replace `|| vec![]` with `Vec::new` - span_lint_and_sugg( - cx, - REDUNDANT_CLOSURE, - expr.span, - "redundant closure", - "replace the closure with `Vec::new`", - "std::vec::Vec::new".into(), - Applicability::MachineApplicable, - ); + if decl.inputs.is_empty() { + if let Some(VecArgs::Vec(&[])) = higher::vec_macro(cx, ex) { + // replace `|| vec![]` with `Vec::new` + span_lint_and_sugg( + cx, + REDUNDANT_CLOSURE, + expr.span, + "redundant closure", + "replace the closure with `Vec::new`", + "std::vec::Vec::new".into(), + Applicability::MachineApplicable, + ); + } } // skip `foo(|| macro!())` return; @@ -188,9 +190,10 @@ fn get_ufcs_type_name(cx: &LateContext<'_>, method_def_id: def_id::DefId, self_a cx.tcx.impl_of_method(method_def_id).and_then(|_| { //a type may implicitly implement other type's methods (e.g. Deref) if match_types(expected_type_of_self, actual_type_of_self) { - return Some(get_type_name(cx, actual_type_of_self)); + Some(get_type_name(cx, actual_type_of_self)) + } else { + None } - None }) } diff --git a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs index 41acf55dd7d..5fdf5bc9e9d 100644 --- a/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs +++ b/src/tools/clippy/clippy_lints/src/eval_order_dependence.rs @@ -110,7 +110,7 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> { self.visit_expr(e); for arm in arms { if let Some(Guard::If(if_expr)) = arm.guard { - self.visit_expr(if_expr) + self.visit_expr(if_expr); } // make sure top level arm expressions aren't linted self.maybe_walk_expr(&*arm.body); diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs index e0b687b0205..e38384b01d4 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -1,4 +1,4 @@ -use crate::consts::{ +use clippy_utils::consts::{ constant, constant_simple, Constant, Constant::{Int, F32, F64}, }; @@ -323,7 +323,7 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { cx, SUBOPTIMAL_FLOPS, parent.span, - "square can be computed more efficiently", + "multiply and add expressions can be calculated more efficiently and accurately", "consider using", format!( "{}.mul_add({}, {})", @@ -337,16 +337,6 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, args: &[Expr<'_>]) { return; } } - - span_lint_and_sugg( - cx, - SUBOPTIMAL_FLOPS, - expr.span, - "square can be computed more efficiently", - "consider using", - format!("{} * {}", Sugg::hir(cx, &args[0], ".."), Sugg::hir(cx, &args[0], "..")), - Applicability::MachineApplicable, - ); } } } diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs index 20288427b4a..7f4fb68cf2f 100644 --- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs +++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs @@ -240,7 +240,7 @@ impl<'a, 'tcx> intravisit::Visitor<'tcx> for StaticMutVisitor<'a, 'tcx> { } }, Assign(target, ..) | AssignOp(_, target, _) | AddrOf(_, hir::Mutability::Mut, target) => { - self.mutates_static |= is_mutated_static(target) + self.mutates_static |= is_mutated_static(target); }, _ => {}, } diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs index b8ea6990866..af759a48e10 100644 --- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs +++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs @@ -116,7 +116,7 @@ impl<'a, 'tcx> DerefVisitor<'a, 'tcx> { self.cx, NOT_UNSAFE_PTR_ARG_DEREF, ptr.span, - "this public function dereferences a raw pointer but is not marked `unsafe`", + "this public function might dereference a raw pointer but is not marked `unsafe`", ); } } diff --git a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs index aa5494d5a7d..a666fee1a4a 100644 --- a/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs +++ b/src/tools/clippy/clippy_lints/src/functions/too_many_lines.rs @@ -4,7 +4,7 @@ use rustc_middle::lint::in_external_macro; use rustc_span::Span; use clippy_utils::diagnostics::span_lint; -use clippy_utils::source::snippet; +use clippy_utils::source::snippet_opt; use super::TOO_MANY_LINES; @@ -13,15 +13,25 @@ pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<' return; } - let code_snippet = snippet(cx, body.value.span, ".."); + let code_snippet = match snippet_opt(cx, body.value.span) { + Some(s) => s, + _ => return, + }; let mut line_count: u64 = 0; let mut in_comment = false; let mut code_in_line; - // Skip the surrounding function decl. - let start_brace_idx = code_snippet.find('{').map_or(0, |i| i + 1); - let end_brace_idx = code_snippet.rfind('}').unwrap_or_else(|| code_snippet.len()); - let function_lines = code_snippet[start_brace_idx..end_brace_idx].lines(); + let function_lines = if matches!(body.value.kind, hir::ExprKind::Block(..)) + && code_snippet.as_bytes().first().copied() == Some(b'{') + && code_snippet.as_bytes().last().copied() == Some(b'}') + { + // Removing the braces from the enclosing block + &code_snippet[1..code_snippet.len() - 1] + } else { + &code_snippet + } + .trim() // Remove leading and trailing blank lines + .lines(); for mut line in function_lines { code_in_line = false; @@ -63,6 +73,6 @@ pub(super) fn check_fn(cx: &LateContext<'_>, span: Span, body: &'tcx hir::Body<' "this function has too many lines ({}/{})", line_count, too_many_lines_threshold ), - ) + ); } } diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index 04730ace887..515b8887453 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -102,7 +102,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { )); } } - }) + }); }, ); } diff --git a/src/tools/clippy/clippy_lints/src/identity_op.rs b/src/tools/clippy/clippy_lints/src/identity_op.rs index 366b3b46a8a..99c461930e4 100644 --- a/src/tools/clippy/clippy_lints/src/identity_op.rs +++ b/src/tools/clippy/clippy_lints/src/identity_op.rs @@ -6,7 +6,7 @@ use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use crate::consts::{constant_simple, Constant}; +use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{clip, unsext}; diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs index 30174fa2100..f2f830ca5c0 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_return.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs @@ -67,7 +67,7 @@ fn lint_break(cx: &LateContext<'_>, break_span: Span, expr_span: Span) { "change `break` to `return` as shown", format!("return {}", snip), app, - ) + ); } #[derive(Clone, Copy, PartialEq, Eq)] @@ -147,7 +147,11 @@ fn lint_implicit_returns( visit_break_exprs(block, |break_expr, dest, sub_expr| { if dest.target_id.ok() == Some(expr.hir_id) { if call_site_span.is_none() && break_expr.span.ctxt() == ctxt { - lint_break(cx, break_expr.span, sub_expr.unwrap().span); + // At this point sub_expr can be `None` in async functions which either diverge, or return the + // unit type. + if let Some(sub_expr) = sub_expr { + lint_break(cx, break_expr.span, sub_expr.span); + } } else { // the break expression is from a macro call, add a return to the loop add_return = true; diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs index d138c3a8acf..3b635071f28 100644 --- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs @@ -58,7 +58,7 @@ declare_clippy_lint! { /// Foo { x, y }; /// ``` pub INCONSISTENT_STRUCT_CONSTRUCTOR, - style, + pedantic, "the order of the field init shorthand is inconsistent with the order in the struct definition" } diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index 1c54599abc4..bfa284f333a 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -1,6 +1,6 @@ //! lint on indexing and slicing operations -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::higher; use rustc_ast::ast::RangeLimits; diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs index afee20ce43e..6b887da2630 100644 --- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs +++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for InfiniteIter { return; }, }; - span_lint(cx, lint, expr.span, msg) + span_lint(cx, lint, expr.span, msg); } } diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index 4e0b1ae78df..ee41c4aea2f 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -1,12 +1,13 @@ //! lint on inherent implementations -use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::in_macro; -use rustc_hir::def_id::DefIdMap; -use rustc_hir::{Crate, Impl, Item, ItemKind}; +use clippy_utils::diagnostics::span_lint_and_note; +use clippy_utils::{in_macro, is_allowed}; +use rustc_data_structures::fx::FxHashMap; +use rustc_hir::{def_id::LocalDefId, Crate, Item, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_session::{declare_tool_lint, impl_lint_pass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; +use std::collections::hash_map::Entry; declare_clippy_lint! { /// **What it does:** Checks for multiple inherent implementations of a struct @@ -40,51 +41,96 @@ declare_clippy_lint! { "Multiple inherent impl that could be grouped" } -#[allow(clippy::module_name_repetitions)] -#[derive(Default)] -pub struct MultipleInherentImpl { - impls: DefIdMap<Span>, -} - -impl_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]); +declare_lint_pass!(MultipleInherentImpl => [MULTIPLE_INHERENT_IMPL]); impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { - fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let ItemKind::Impl(Impl { - ref generics, - of_trait: None, - .. - }) = item.kind + fn check_crate_post(&mut self, cx: &LateContext<'tcx>, _: &'tcx Crate<'_>) { + // Map from a type to it's first impl block. Needed to distinguish generic arguments. + // e.g. `Foo<Bar>` and `Foo<Baz>` + let mut type_map = FxHashMap::default(); + // List of spans to lint. (lint_span, first_span) + let mut lint_spans = Vec::new(); + + for (_, impl_ids) in cx + .tcx + .crate_inherent_impls(()) + .inherent_impls + .iter() + .filter(|(&id, impls)| { + impls.len() > 1 + // Check for `#[allow]` on the type definition + && !is_allowed( + cx, + MULTIPLE_INHERENT_IMPL, + cx.tcx.hir().local_def_id_to_hir_id(id), + ) + }) { - // Remember for each inherent implementation encountered its span and generics - // but filter out implementations that have generic params (type or lifetime) - // or are derived from a macro - if !in_macro(item.span) && generics.params.is_empty() { - self.impls.insert(item.def_id.to_def_id(), item.span); + for impl_id in impl_ids.iter().map(|id| id.expect_local()) { + match type_map.entry(cx.tcx.type_of(impl_id)) { + Entry::Vacant(e) => { + // Store the id for the first impl block of this type. The span is retrieved lazily. + e.insert(IdOrSpan::Id(impl_id)); + }, + Entry::Occupied(mut e) => { + if let Some(span) = get_impl_span(cx, impl_id) { + let first_span = match *e.get() { + IdOrSpan::Span(s) => s, + IdOrSpan::Id(id) => { + if let Some(s) = get_impl_span(cx, id) { + // Remember the span of the first block. + *e.get_mut() = IdOrSpan::Span(s); + s + } else { + // The first impl block isn't considered by the lint. Replace it with the + // current one. + *e.get_mut() = IdOrSpan::Span(span); + continue; + } + }, + }; + lint_spans.push((span, first_span)); + } + }, + } } + + // Switching to the next type definition, no need to keep the current entries around. + type_map.clear(); } - } - fn check_crate_post(&mut self, cx: &LateContext<'tcx>, krate: &'tcx Crate<'_>) { - if !krate.items.is_empty() { - // Retrieve all inherent implementations from the crate, grouped by type - for impls in cx.tcx.crate_inherent_impls(()).inherent_impls.values() { - // Filter out implementations that have generic params (type or lifetime) - let mut impl_spans = impls.iter().filter_map(|impl_def| self.impls.get(impl_def)); - if let Some(initial_span) = impl_spans.next() { - impl_spans.for_each(|additional_span| { - span_lint_and_then( - cx, - MULTIPLE_INHERENT_IMPL, - *additional_span, - "multiple implementations of this structure", - |diag| { - diag.span_note(*initial_span, "first implementation here"); - }, - ) - }) - } - } + // `TyCtxt::crate_inherent_impls` doesn't have a defined order. Sort the lint output first. + lint_spans.sort_by_key(|x| x.0.lo()); + for (span, first_span) in lint_spans { + span_lint_and_note( + cx, + MULTIPLE_INHERENT_IMPL, + span, + "multiple implementations of this structure", + Some(first_span), + "first implementation here", + ); } } } + +/// Gets the span for the given impl block unless it's not being considered by the lint. +fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option<Span> { + let id = cx.tcx.hir().local_def_id_to_hir_id(id); + if let Node::Item(&Item { + kind: ItemKind::Impl(ref impl_item), + span, + .. + }) = cx.tcx.hir().get(id) + { + (!in_macro(span) && impl_item.generics.params.is_empty() && !is_allowed(cx, MULTIPLE_INHERENT_IMPL, id)) + .then(|| span) + } else { + None + } +} + +enum IdOrSpan { + Id(LocalDefId), + Span(Span), +} diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs index c67c02eefa5..37011f5578d 100644 --- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs @@ -7,9 +7,8 @@ use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::Span; use rustc_target::abi::LayoutOf; -use crate::consts::{constant, Constant}; - use clippy_utils::comparisons::Rel; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::source::snippet; use clippy_utils::{comparisons, sext}; @@ -177,7 +176,7 @@ fn upcast_comparison_bounds_err<'tcx>( }, Rel::Eq | Rel::Ne => unreachable!(), } { - err_upcast_comparison(cx, span, lhs, true) + err_upcast_comparison(cx, span, lhs, true); } else if match rel { Rel::Lt => { if invert { @@ -195,7 +194,7 @@ fn upcast_comparison_bounds_err<'tcx>( }, Rel::Eq | Rel::Ne => unreachable!(), } { - err_upcast_comparison(cx, span, lhs, false) + err_upcast_comparison(cx, span, lhs, false); } } } diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index bb57adff7be..583514b22f9 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -380,9 +380,9 @@ fn check_cmp(cx: &LateContext<'_>, span: Span, method: &Expr<'_>, lit: &Expr<'_> } } - check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to) + check_len(cx, span, method_path.ident.name, args, &lit.node, op, compare_to); } else { - check_empty_expr(cx, span, method, lit, op) + check_empty_expr(cx, span, method, lit, op); } } diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 17e23781db7..e627b1385bc 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -135,7 +135,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { None, "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" - ) + ); } else if init_ty.needs_drop(cx.tcx, cx.param_env) { span_lint_and_help( cx, @@ -145,7 +145,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { None, "consider using an underscore-prefixed named \ binding or dropping explicitly with `std::mem::drop`" - ) + ); } else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) { span_lint_and_help( cx, @@ -154,7 +154,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding let on an expression with `#[must_use]` type", None, "consider explicitly using expression value" - ) + ); } else if is_must_use_func_call(cx, init) { span_lint_and_help( cx, @@ -163,7 +163,7 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { "non-binding let on a result of a `#[must_use]` function", None, "consider explicitly using function result" - ) + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 725aa54157e..e7dd3952b3a 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -6,7 +6,6 @@ #![feature(in_band_lifetimes)] #![feature(iter_zip)] #![feature(once_cell)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(rustc_private)] #![feature(stmt_expr_attributes)] #![feature(control_flow_enum)] @@ -42,6 +41,9 @@ extern crate rustc_target; extern crate rustc_trait_selection; extern crate rustc_typeck; +#[macro_use] +extern crate clippy_utils; + use clippy_utils::parse_msrv; use rustc_data_structures::fx::FxHashSet; use rustc_lint::LintId; @@ -146,22 +148,8 @@ macro_rules! declare_clippy_lint { }; } -#[macro_export] -macro_rules! sym { - ( $($x:tt)* ) => { clippy_utils::sym!($($x)*) } -} - -#[macro_export] -macro_rules! unwrap_cargo_metadata { - ( $($x:tt)* ) => { clippy_utils::unwrap_cargo_metadata!($($x)*) } -} - -macro_rules! extract_msrv_attr { - ( $($x:tt)* ) => { clippy_utils::extract_msrv_attr!($($x)*); } -} - -mod consts; -#[macro_use] +#[cfg(feature = "metadata-collector-lint")] +mod deprecated_lints; mod utils; // begin lints modules, do not remove this comment, it’s used in `update_lints` @@ -289,6 +277,7 @@ mod mut_reference; mod mutable_debug_assertion; mod mutex_atomic; mod needless_arbitrary_self_type; +mod needless_bitwise_bool; mod needless_bool; mod needless_borrow; mod needless_borrowed_ref; @@ -363,6 +352,7 @@ mod unnecessary_sort_by; mod unnecessary_wraps; mod unnested_or_patterns; mod unsafe_removed_from_name; +mod unused_async; mod unused_io_amount; mod unused_self; mod unused_unit; @@ -402,7 +392,6 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore) { #[doc(hidden)] pub fn read_conf(sess: &Session) -> Conf { - use std::path::Path; let file_name = match utils::conf::lookup_conf_file() { Ok(Some(path)) => path, Ok(None) => return Conf::default(), @@ -413,16 +402,6 @@ pub fn read_conf(sess: &Session) -> Conf { }, }; - let file_name = if file_name.is_relative() { - sess.local_crate_source_file - .as_deref() - .and_then(Path::parent) - .unwrap_or_else(|| Path::new("")) - .join(file_name) - } else { - file_name - }; - let TryConf { conf, errors } = 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 { @@ -502,6 +481,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: "clippy::filter_map", "this lint has been replaced by `manual_filter_map`, a more specific lint", ); + store.register_removed( + "clippy::pub_enum_variant_names", + "set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items", + ); + store.register_removed( + "clippy::wrong_pub_self_convention", + "set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items", + ); // end deprecated lints, do not remove this comment, it’s used in `update_lints` // begin register lints, do not remove this comment, it’s used in `update_lints` @@ -615,7 +602,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: enum_variants::ENUM_VARIANT_NAMES, enum_variants::MODULE_INCEPTION, enum_variants::MODULE_NAME_REPETITIONS, - enum_variants::PUB_ENUM_VARIANT_NAMES, eq_op::EQ_OP, eq_op::OP_REF, erasing_op::ERASING_OP, @@ -776,6 +762,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: methods::MANUAL_FILTER_MAP, methods::MANUAL_FIND_MAP, methods::MANUAL_SATURATING_ARITHMETIC, + methods::MANUAL_STR_REPEAT, methods::MAP_COLLECT_RESULT_UNIT, methods::MAP_FLATTEN, methods::MAP_UNWRAP_OR, @@ -793,13 +780,13 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: methods::SKIP_WHILE_NEXT, methods::STRING_EXTEND_CHARS, methods::SUSPICIOUS_MAP, + methods::SUSPICIOUS_SPLITN, methods::UNINIT_ASSUMED_INIT, methods::UNNECESSARY_FILTER_MAP, methods::UNNECESSARY_FOLD, methods::UNNECESSARY_LAZY_EVALUATIONS, methods::UNWRAP_USED, methods::USELESS_ASREF, - methods::WRONG_PUB_SELF_CONVENTION, methods::WRONG_SELF_CONVENTION, methods::ZST_OFFSET, minmax::MIN_MAX, @@ -834,9 +821,11 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: mutex_atomic::MUTEX_ATOMIC, mutex_atomic::MUTEX_INTEGER, needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE, + needless_bitwise_bool::NEEDLESS_BITWISE_BOOL, needless_bool::BOOL_COMPARISON, needless_bool::NEEDLESS_BOOL, needless_borrow::NEEDLESS_BORROW, + needless_borrow::REF_BINDING_TO_REFERENCE, needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE, needless_continue::NEEDLESS_CONTINUE, needless_for_each::NEEDLESS_FOR_EACH, @@ -960,6 +949,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: unnecessary_wraps::UNNECESSARY_WRAPS, unnested_or_patterns::UNNESTED_OR_PATTERNS, unsafe_removed_from_name::UNSAFE_REMOVED_FROM_NAME, + unused_async::UNUSED_ASYNC, unused_io_amount::UNUSED_IO_AMOUNT, unused_self::UNUSED_SELF, unused_unit::UNUSED_UNIT, @@ -990,289 +980,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: ]); // end register lints, do not remove this comment, it’s used in `update_lints` - // all the internal lints - #[cfg(feature = "internal-lints")] - { - store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal); - store.register_early_pass(|| box utils::internal_lints::ProduceIce); - store.register_late_pass(|| box utils::inspector::DeepCodeInspector); - store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); - store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new()); - store.register_late_pass(|| box utils::internal_lints::IfChainStyle); - store.register_late_pass(|| box utils::internal_lints::InvalidPaths); - store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default()); - store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default()); - store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem); - store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass); - } - #[cfg(feature = "metadata-collector-lint")] - { - if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) { - store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::default()); - } - } - - store.register_late_pass(|| box utils::author::Author); - store.register_late_pass(|| box await_holding_invalid::AwaitHolding); - store.register_late_pass(|| box serde_api::SerdeApi); - let vec_box_size_threshold = conf.vec_box_size_threshold; - let type_complexity_threshold = conf.type_complexity_threshold; - store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold)); - store.register_late_pass(|| box booleans::NonminimalBool); - store.register_late_pass(|| box eq_op::EqOp); - store.register_late_pass(|| box enum_clike::UnportableVariant); - store.register_late_pass(|| box float_literal::FloatLiteral); - let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; - store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold)); - store.register_late_pass(|| box ptr::Ptr); - store.register_late_pass(|| box ptr_eq::PtrEq); - store.register_late_pass(|| box needless_bool::NeedlessBool); - store.register_late_pass(|| box needless_bool::BoolComparison); - store.register_late_pass(|| box needless_for_each::NeedlessForEach); - store.register_late_pass(|| box approx_const::ApproxConstant); - store.register_late_pass(|| box misc::MiscLints); - store.register_late_pass(|| box eta_reduction::EtaReduction); - store.register_late_pass(|| box identity_op::IdentityOp); - store.register_late_pass(|| box erasing_op::ErasingOp); - store.register_late_pass(|| box mut_mut::MutMut); - store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed); - store.register_late_pass(|| box len_zero::LenZero); - store.register_late_pass(|| box attrs::Attributes); - store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions); - store.register_late_pass(|| box collapsible_match::CollapsibleMatch); - store.register_late_pass(|| box unicode::Unicode); - store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd); - store.register_late_pass(|| box strings::StringAdd); - store.register_late_pass(|| box implicit_return::ImplicitReturn); - store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub); - store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback); - store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor); - store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions); - store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports); - - let msrv = conf.msrv.as_ref().and_then(|s| { - parse_msrv(s, None, None).or_else(|| { - sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s)); - None - }) - }); - - store.register_late_pass(move || box methods::Methods::new(msrv)); - store.register_late_pass(move || box matches::Matches::new(msrv)); - store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv)); - store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv)); - store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv)); - store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv)); - store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv)); - store.register_late_pass(move || box mem_replace::MemReplace::new(msrv)); - store.register_late_pass(move || box ranges::Ranges::new(msrv)); - store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv)); - store.register_late_pass(move || box use_self::UseSelf::new(msrv)); - store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv)); - store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark); - store.register_late_pass(move || box casts::Casts::new(msrv)); - store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv)); - - store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount); - store.register_late_pass(|| box map_clone::MapClone); - store.register_late_pass(|| box map_err_ignore::MapErrIgnore); - store.register_late_pass(|| box shadow::Shadow); - store.register_late_pass(|| box unit_types::UnitTypes); - store.register_late_pass(|| box loops::Loops); - store.register_late_pass(|| box main_recursion::MainRecursion::default()); - store.register_late_pass(|| box lifetimes::Lifetimes); - store.register_late_pass(|| box entry::HashMapPass); - store.register_late_pass(|| box minmax::MinMaxPass); - store.register_late_pass(|| box open_options::OpenOptions); - store.register_late_pass(|| box zero_div_zero::ZeroDiv); - store.register_late_pass(|| box mutex_atomic::Mutex); - store.register_late_pass(|| box needless_update::NeedlessUpdate); - store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default()); - store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef); - store.register_late_pass(|| box no_effect::NoEffect); - store.register_late_pass(|| box temporary_assignment::TemporaryAssignment); - store.register_late_pass(|| box transmute::Transmute); - let cognitive_complexity_threshold = conf.cognitive_complexity_threshold; - store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold)); - let too_large_for_stack = conf.too_large_for_stack; - store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack}); - store.register_late_pass(move || box vec::UselessVec{too_large_for_stack}); - store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented); - store.register_late_pass(|| box strings::StringLitAsBytes); - store.register_late_pass(|| box derive::Derive); - store.register_late_pass(|| box get_last_with_len::GetLastWithLen); - store.register_late_pass(|| box drop_forget_ref::DropForgetRef); - store.register_late_pass(|| box empty_enum::EmptyEnum); - store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons); - store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons); - store.register_late_pass(|| box regex::Regex::default()); - store.register_late_pass(|| box copies::CopyAndPaste); - store.register_late_pass(|| box copy_iterator::CopyIterator); - store.register_late_pass(|| box format::UselessFormat); - store.register_late_pass(|| box swap::Swap); - store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional); - store.register_late_pass(|| box new_without_default::NewWithoutDefault::default()); - let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>(); - store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_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 || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold)); - let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>(); - store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone())); - store.register_late_pass(|| box neg_multiply::NegMultiply); - store.register_late_pass(|| box mem_discriminant::MemDiscriminant); - store.register_late_pass(|| box mem_forget::MemForget); - store.register_late_pass(|| box arithmetic::Arithmetic::default()); - store.register_late_pass(|| box assign_ops::AssignOps); - store.register_late_pass(|| box let_if_seq::LetIfSeq); - store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence); - store.register_late_pass(|| box missing_doc::MissingDoc::new()); - store.register_late_pass(|| box missing_inline::MissingInline); - store.register_late_pass(move || box exhaustive_items::ExhaustiveItems); - store.register_late_pass(|| box if_let_some_result::OkIfLet); - store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl); - store.register_late_pass(|| box unused_io_amount::UnusedIoAmount); - let enum_variant_size_threshold = conf.enum_variant_size_threshold; - store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)); - store.register_late_pass(|| box explicit_write::ExplicitWrite); - store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue); - let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new( - conf.trivial_copy_size_limit, - conf.pass_by_value_size_limit, - &sess.target, - ); - store.register_late_pass(move || box pass_by_ref_or_value); - store.register_late_pass(|| box ref_option_ref::RefOptionRef); - store.register_late_pass(|| box try_err::TryErr); - store.register_late_pass(|| box bytecount::ByteCount); - store.register_late_pass(|| box infinite_iter::InfiniteIter); - store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody); - store.register_late_pass(|| box useless_conversion::UselessConversion::default()); - store.register_late_pass(|| box implicit_hasher::ImplicitHasher); - store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom); - store.register_late_pass(|| box double_comparison::DoubleComparisons); - store.register_late_pass(|| box question_mark::QuestionMark); - store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings); - store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl); - store.register_late_pass(|| box map_unit_fn::MapUnit); - store.register_late_pass(|| box inherent_impl::MultipleInherentImpl::default()); - store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd); - store.register_late_pass(|| box unwrap::Unwrap); - store.register_late_pass(|| box duration_subsec::DurationSubsec); - store.register_late_pass(|| box indexing_slicing::IndexingSlicing); - store.register_late_pass(|| box non_copy_const::NonCopyConst); - store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast); - store.register_late_pass(|| box redundant_clone::RedundantClone); - store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit); - store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy); - store.register_late_pass(|| box unnecessary_wraps::UnnecessaryWraps); - store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); - store.register_late_pass(|| box transmuting_null::TransmutingNull); - store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite); - store.register_late_pass(|| box integer_division::IntegerDivision); - store.register_late_pass(|| box inherent_to_string::InherentToString); - let max_trait_bounds = conf.max_trait_bounds; - store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds)); - store.register_late_pass(|| box comparison_chain::ComparisonChain); - store.register_late_pass(|| box mut_key::MutableKeyType); - store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic); - store.register_early_pass(|| box reference::DerefAddrOf); - store.register_early_pass(|| box reference::RefInDeref); - store.register_early_pass(|| box double_parens::DoubleParens); - store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new()); - store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval); - store.register_early_pass(|| box if_not_else::IfNotElse); - store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse); - store.register_early_pass(|| box int_plus_one::IntPlusOne); - store.register_early_pass(|| box formatting::Formatting); - store.register_early_pass(|| box misc_early::MiscEarlyLints); - store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall); - store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall); - store.register_early_pass(|| box unused_unit::UnusedUnit); - store.register_late_pass(|| box returns::Return); - store.register_early_pass(|| box collapsible_if::CollapsibleIf); - store.register_early_pass(|| box items_after_statements::ItemsAfterStatements); - store.register_early_pass(|| box precedence::Precedence); - store.register_early_pass(|| box needless_continue::NeedlessContinue); - store.register_early_pass(|| box redundant_else::RedundantElse); - store.register_late_pass(|| box create_dir::CreateDir); - store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType); - let cargo_ignore_publish = conf.cargo_ignore_publish; - store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish)); - store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions); - store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies); - let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions; - store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability)); - let literal_representation_threshold = conf.literal_representation_threshold; - store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold)); - let enum_variant_name_threshold = conf.enum_variant_name_threshold; - store.register_early_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold)); - store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments); - let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive; - store.register_early_pass(move || box upper_case_acronyms::UpperCaseAcronyms::new(upper_case_acronyms_aggressive)); - store.register_late_pass(|| box default::Default::default()); - store.register_late_pass(|| box unused_self::UnusedSelf); - store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall); - store.register_late_pass(|| box exit::Exit); - store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome); - let array_size_threshold = conf.array_size_threshold; - store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold)); - store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold)); - store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic); - store.register_early_pass(|| box as_conversions::AsConversions); - store.register_late_pass(|| box let_underscore::LetUnderscore); - store.register_late_pass(|| box atomic_ordering::AtomicOrdering); - store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports); - let max_fn_params_bools = conf.max_fn_params_bools; - let max_struct_bools = conf.max_struct_bools; - store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools)); - store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap); - let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports; - store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)); - store.register_late_pass(|| box verbose_file_reads::VerboseFileReads); - store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default()); - store.register_late_pass(|| box unnamed_address::UnnamedAddress); - store.register_late_pass(|| box dereference::Dereferencing::default()); - store.register_late_pass(|| box option_if_let_else::OptionIfLetElse); - store.register_late_pass(|| box future_not_send::FutureNotSend); - store.register_late_pass(|| box if_let_mutex::IfLetMutex); - store.register_late_pass(|| box mut_mutex_lock::MutMutexLock); - store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems); - store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); - store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); - store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn); - let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; - store.register_early_pass(move || box non_expressive_names::NonExpressiveNames { - single_char_binding_names_threshold, - }); - store.register_late_pass(|| box macro_use::MacroUseImports::default()); - store.register_late_pass(|| box map_identity::MapIdentity); - store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch); - store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive); - store.register_late_pass(|| box repeat_once::RepeatOnce); - store.register_late_pass(|| box unwrap_in_result::UnwrapInResult); - store.register_late_pass(|| box self_assignment::SelfAssignment); - store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr); - store.register_late_pass(|| box manual_ok_or::ManualOkOr); - store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); - store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned); - store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); - let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>(); - store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods)); - store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax); - store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax); - store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops); - store.register_late_pass(|| box strings::StrToString); - store.register_late_pass(|| box strings::StringToString); - store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues); - store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default()); - store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons); - store.register_late_pass(|| box redundant_slicing::RedundantSlicing); - store.register_late_pass(|| box from_str_radix_10::FromStrRadix10); - store.register_late_pass(|| box manual_map::ManualMap); - store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv)); - store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison); - store.register_group(true, "clippy::restriction", Some("clippy_restriction"), vec![ LintId::of(arithmetic::FLOAT_ARITHMETIC), LintId::of(arithmetic::INTEGER_ARITHMETIC), @@ -1303,7 +1010,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::FILETYPE_IS_FILE), LintId::of(methods::GET_UNWRAP), LintId::of(methods::UNWRAP_USED), - LintId::of(methods::WRONG_PUB_SELF_CONVENTION), LintId::of(misc::FLOAT_CMP_CONST), LintId::of(misc_early::UNNEEDED_FIELD_PATTERN), LintId::of(missing_doc::MISSING_DOCS_IN_PRIVATE_ITEMS), @@ -1315,7 +1021,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(panic_unimplemented::UNIMPLEMENTED), LintId::of(panic_unimplemented::UNREACHABLE), LintId::of(pattern_type_mismatch::PATTERN_TYPE_MISMATCH), - LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), LintId::of(shadow::SHADOW_REUSE), LintId::of(shadow::SHADOW_SAME), LintId::of(strings::STRING_ADD), @@ -1356,7 +1061,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(doc::MISSING_PANICS_DOC), LintId::of(empty_enum::EMPTY_ENUM), LintId::of(enum_variants::MODULE_NAME_REPETITIONS), - LintId::of(enum_variants::PUB_ENUM_VARIANT_NAMES), LintId::of(eta_reduction::REDUNDANT_CLOSURE_FOR_METHOD_CALLS), LintId::of(excessive_bools::FN_PARAMS_EXCESSIVE_BOOLS), LintId::of(excessive_bools::STRUCT_EXCESSIVE_BOOLS), @@ -1365,6 +1069,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(if_not_else::IF_NOT_ELSE), LintId::of(implicit_hasher::IMPLICIT_HASHER), LintId::of(implicit_saturating_sub::IMPLICIT_SATURATING_SUB), + LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), LintId::of(infinite_iter::MAYBE_INFINITE_ITER), LintId::of(invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS), LintId::of(items_after_statements::ITEMS_AFTER_STATEMENTS), @@ -1392,6 +1097,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(misc::USED_UNDERSCORE_BINDING), LintId::of(misc_early::UNSEPARATED_LITERAL_SUFFIX), LintId::of(mut_mut::MUT_MUT), + LintId::of(needless_bitwise_bool::NEEDLESS_BITWISE_BOOL), + LintId::of(needless_borrow::REF_BINDING_TO_REFERENCE), LintId::of(needless_continue::NEEDLESS_CONTINUE), LintId::of(needless_for_each::NEEDLESS_FOR_EACH), LintId::of(needless_pass_by_value::NEEDLESS_PASS_BY_VALUE), @@ -1403,6 +1110,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(ranges::RANGE_PLUS_ONE), LintId::of(redundant_else::REDUNDANT_ELSE), LintId::of(ref_option_ref::REF_OPTION_REF), + LintId::of(semicolon_if_nothing_returned::SEMICOLON_IF_NOTHING_RETURNED), LintId::of(shadow::SHADOW_UNRELATED), LintId::of(strings::STRING_ADD_ASSIGN), LintId::of(trait_bounds::TRAIT_DUPLICATION_IN_BOUNDS), @@ -1415,6 +1123,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(unit_types::LET_UNIT_VALUE), LintId::of(unnecessary_wraps::UNNECESSARY_WRAPS), LintId::of(unnested_or_patterns::UNNESTED_OR_PATTERNS), + LintId::of(unused_async::UNUSED_ASYNC), LintId::of(unused_self::UNUSED_SELF), LintId::of(wildcard_imports::ENUM_GLOB_USE), LintId::of(wildcard_imports::WILDCARD_IMPORTS), @@ -1511,7 +1220,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(identity_op::IDENTITY_OP), LintId::of(if_let_mutex::IF_LET_MUTEX), LintId::of(if_let_some_result::IF_LET_SOME_RESULT), - LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), LintId::of(indexing_slicing::OUT_OF_BOUNDS_INDEXING), LintId::of(infinite_iter::INFINITE_ITER), LintId::of(inherent_to_string::INHERENT_TO_STRING), @@ -1591,6 +1299,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::MANUAL_FILTER_MAP), LintId::of(methods::MANUAL_FIND_MAP), LintId::of(methods::MANUAL_SATURATING_ARITHMETIC), + LintId::of(methods::MANUAL_STR_REPEAT), LintId::of(methods::MAP_COLLECT_RESULT_UNIT), LintId::of(methods::NEW_RET_NO_SELF), LintId::of(methods::OK_EXPECT), @@ -1606,6 +1315,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(methods::SKIP_WHILE_NEXT), LintId::of(methods::STRING_EXTEND_CHARS), LintId::of(methods::SUSPICIOUS_MAP), + LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), LintId::of(methods::UNNECESSARY_FILTER_MAP), LintId::of(methods::UNNECESSARY_FOLD), @@ -1635,6 +1345,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE), LintId::of(needless_bool::BOOL_COMPARISON), LintId::of(needless_bool::NEEDLESS_BOOL), + LintId::of(needless_borrow::NEEDLESS_BORROW), LintId::of(needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE), LintId::of(needless_question_mark::NEEDLESS_QUESTION_MARK), LintId::of(needless_update::NEEDLESS_UPDATE), @@ -1681,7 +1392,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(slow_vector_initialization::SLOW_VECTOR_INITIALIZATION), LintId::of(stable_sort_primitive::STABLE_SORT_PRIMITIVE), LintId::of(strings::STRING_FROM_UTF8_AS_BYTES), - LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), LintId::of(suspicious_trait_impl::SUSPICIOUS_ARITHMETIC_IMPL), LintId::of(suspicious_trait_impl::SUSPICIOUS_OP_ASSIGN_IMPL), LintId::of(swap::ALMOST_SWAPPED), @@ -1764,7 +1474,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(functions::MUST_USE_UNIT), LintId::of(functions::RESULT_UNIT_ERR), LintId::of(if_let_some_result::IF_LET_SOME_RESULT), - LintId::of(inconsistent_struct_constructor::INCONSISTENT_STRUCT_CONSTRUCTOR), LintId::of(inherent_to_string::INHERENT_TO_STRING), LintId::of(len_zero::COMPARISON_TO_EMPTY), LintId::of(len_zero::LEN_WITHOUT_IS_EMPTY), @@ -1819,6 +1528,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(misc_early::REDUNDANT_PATTERN), LintId::of(mut_mutex_lock::MUT_MUTEX_LOCK), LintId::of(mut_reference::UNNECESSARY_MUT_PASSED), + LintId::of(needless_borrow::NEEDLESS_BORROW), LintId::of(neg_multiply::NEG_MULTIPLY), LintId::of(new_without_default::NEW_WITHOUT_DEFAULT), LintId::of(non_copy_const::BORROW_INTERIOR_MUTABLE_CONST), @@ -1835,7 +1545,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(returns::LET_AND_RETURN), LintId::of(returns::NEEDLESS_RETURN), LintId::of(single_component_path_imports::SINGLE_COMPONENT_PATH_IMPORTS), - LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), LintId::of(tabs_in_doc_comments::TABS_IN_DOC_COMMENTS), LintId::of(to_digit_is_some::TO_DIGIT_IS_SOME), LintId::of(try_err::TRY_ERR), @@ -1983,6 +1692,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(mem_replace::MEM_REPLACE_WITH_UNINIT), LintId::of(methods::CLONE_DOUBLE_REF), LintId::of(methods::ITERATOR_STEP_BY_ZERO), + LintId::of(methods::SUSPICIOUS_SPLITN), LintId::of(methods::UNINIT_ASSUMED_INIT), LintId::of(methods::ZST_OFFSET), LintId::of(minmax::MIN_MAX), @@ -2027,6 +1737,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(loops::NEEDLESS_COLLECT), LintId::of(methods::EXPECT_FUN_CALL), LintId::of(methods::ITER_NTH), + LintId::of(methods::MANUAL_STR_REPEAT), LintId::of(methods::OR_FUN_CALL), LintId::of(methods::SINGLE_CHAR_PATTERN), LintId::of(misc::CMP_OWNED), @@ -2058,14 +1769,304 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: LintId::of(missing_const_for_fn::MISSING_CONST_FOR_FN), LintId::of(mutable_debug_assertion::DEBUG_ASSERT_WITH_MUT_CALL), LintId::of(mutex_atomic::MUTEX_INTEGER), - LintId::of(needless_borrow::NEEDLESS_BORROW), LintId::of(path_buf_push_overwrite::PATH_BUF_PUSH_OVERWRITE), LintId::of(redundant_pub_crate::REDUNDANT_PUB_CRATE), LintId::of(regex::TRIVIAL_REGEX), LintId::of(strings::STRING_LIT_AS_BYTES), + LintId::of(suspicious_operation_groupings::SUSPICIOUS_OPERATION_GROUPINGS), LintId::of(transmute::USELESS_TRANSMUTE), LintId::of(use_self::USE_SELF), ]); + + #[cfg(feature = "metadata-collector-lint")] + { + if std::env::var("ENABLE_METADATA_COLLECTION").eq(&Ok("1".to_string())) { + store.register_late_pass(|| box utils::internal_lints::metadata_collector::MetadataCollector::new()); + return; + } + } + + // all the internal lints + #[cfg(feature = "internal-lints")] + { + store.register_early_pass(|| box utils::internal_lints::ClippyLintsInternal); + store.register_early_pass(|| box utils::internal_lints::ProduceIce); + store.register_late_pass(|| box utils::inspector::DeepCodeInspector); + store.register_late_pass(|| box utils::internal_lints::CollapsibleCalls); + store.register_late_pass(|| box utils::internal_lints::CompilerLintFunctions::new()); + store.register_late_pass(|| box utils::internal_lints::IfChainStyle); + store.register_late_pass(|| box utils::internal_lints::InvalidPaths); + store.register_late_pass(|| box utils::internal_lints::InterningDefinedSymbol::default()); + store.register_late_pass(|| box utils::internal_lints::LintWithoutLintPass::default()); + store.register_late_pass(|| box utils::internal_lints::MatchTypeOnDiagItem); + store.register_late_pass(|| box utils::internal_lints::OuterExpnDataPass); + } + + store.register_late_pass(|| box utils::author::Author); + store.register_late_pass(|| box await_holding_invalid::AwaitHolding); + store.register_late_pass(|| box serde_api::SerdeApi); + let vec_box_size_threshold = conf.vec_box_size_threshold; + let type_complexity_threshold = conf.type_complexity_threshold; + store.register_late_pass(move || box types::Types::new(vec_box_size_threshold, type_complexity_threshold)); + store.register_late_pass(|| box booleans::NonminimalBool); + store.register_late_pass(|| box needless_bitwise_bool::NeedlessBitwiseBool); + store.register_late_pass(|| box eq_op::EqOp); + store.register_late_pass(|| box enum_clike::UnportableVariant); + store.register_late_pass(|| box float_literal::FloatLiteral); + let verbose_bit_mask_threshold = conf.verbose_bit_mask_threshold; + store.register_late_pass(move || box bit_mask::BitMask::new(verbose_bit_mask_threshold)); + store.register_late_pass(|| box ptr::Ptr); + store.register_late_pass(|| box ptr_eq::PtrEq); + store.register_late_pass(|| box needless_bool::NeedlessBool); + store.register_late_pass(|| box needless_bool::BoolComparison); + store.register_late_pass(|| box needless_for_each::NeedlessForEach); + store.register_late_pass(|| box approx_const::ApproxConstant); + store.register_late_pass(|| box misc::MiscLints); + store.register_late_pass(|| box eta_reduction::EtaReduction); + store.register_late_pass(|| box identity_op::IdentityOp); + store.register_late_pass(|| box erasing_op::ErasingOp); + store.register_late_pass(|| box mut_mut::MutMut); + store.register_late_pass(|| box mut_reference::UnnecessaryMutPassed); + store.register_late_pass(|| box len_zero::LenZero); + store.register_late_pass(|| box attrs::Attributes); + store.register_late_pass(|| box blocks_in_if_conditions::BlocksInIfConditions); + store.register_late_pass(|| box collapsible_match::CollapsibleMatch); + store.register_late_pass(|| box unicode::Unicode); + store.register_late_pass(|| box unit_return_expecting_ord::UnitReturnExpectingOrd); + store.register_late_pass(|| box strings::StringAdd); + store.register_late_pass(|| box implicit_return::ImplicitReturn); + store.register_late_pass(|| box implicit_saturating_sub::ImplicitSaturatingSub); + store.register_late_pass(|| box default_numeric_fallback::DefaultNumericFallback); + store.register_late_pass(|| box inconsistent_struct_constructor::InconsistentStructConstructor); + store.register_late_pass(|| box non_octal_unix_permissions::NonOctalUnixPermissions); + store.register_early_pass(|| box unnecessary_self_imports::UnnecessarySelfImports); + + let msrv = conf.msrv.as_ref().and_then(|s| { + parse_msrv(s, None, None).or_else(|| { + sess.err(&format!("error reading Clippy's configuration file. `{}` is not a valid Rust version", s)); + None + }) + }); + + let avoid_breaking_exported_api = conf.avoid_breaking_exported_api; + store.register_late_pass(move || box methods::Methods::new(avoid_breaking_exported_api, msrv)); + store.register_late_pass(move || box matches::Matches::new(msrv)); + store.register_early_pass(move || box manual_non_exhaustive::ManualNonExhaustive::new(msrv)); + store.register_late_pass(move || box manual_strip::ManualStrip::new(msrv)); + store.register_early_pass(move || box redundant_static_lifetimes::RedundantStaticLifetimes::new(msrv)); + store.register_early_pass(move || box redundant_field_names::RedundantFieldNames::new(msrv)); + store.register_late_pass(move || box checked_conversions::CheckedConversions::new(msrv)); + store.register_late_pass(move || box mem_replace::MemReplace::new(msrv)); + store.register_late_pass(move || box ranges::Ranges::new(msrv)); + store.register_late_pass(move || box from_over_into::FromOverInto::new(msrv)); + store.register_late_pass(move || box use_self::UseSelf::new(msrv)); + store.register_late_pass(move || box missing_const_for_fn::MissingConstForFn::new(msrv)); + store.register_late_pass(move || box needless_question_mark::NeedlessQuestionMark); + store.register_late_pass(move || box casts::Casts::new(msrv)); + store.register_early_pass(move || box unnested_or_patterns::UnnestedOrPatterns::new(msrv)); + + store.register_late_pass(|| box size_of_in_element_count::SizeOfInElementCount); + store.register_late_pass(|| box map_clone::MapClone); + store.register_late_pass(|| box map_err_ignore::MapErrIgnore); + store.register_late_pass(|| box shadow::Shadow); + store.register_late_pass(|| box unit_types::UnitTypes); + store.register_late_pass(|| box loops::Loops); + store.register_late_pass(|| box main_recursion::MainRecursion::default()); + store.register_late_pass(|| box lifetimes::Lifetimes); + store.register_late_pass(|| box entry::HashMapPass); + store.register_late_pass(|| box minmax::MinMaxPass); + store.register_late_pass(|| box open_options::OpenOptions); + store.register_late_pass(|| box zero_div_zero::ZeroDiv); + store.register_late_pass(|| box mutex_atomic::Mutex); + store.register_late_pass(|| box needless_update::NeedlessUpdate); + store.register_late_pass(|| box needless_borrow::NeedlessBorrow::default()); + store.register_late_pass(|| box needless_borrowed_ref::NeedlessBorrowedRef); + store.register_late_pass(|| box no_effect::NoEffect); + store.register_late_pass(|| box temporary_assignment::TemporaryAssignment); + store.register_late_pass(|| box transmute::Transmute); + let cognitive_complexity_threshold = conf.cognitive_complexity_threshold; + store.register_late_pass(move || box cognitive_complexity::CognitiveComplexity::new(cognitive_complexity_threshold)); + let too_large_for_stack = conf.too_large_for_stack; + store.register_late_pass(move || box escape::BoxedLocal{too_large_for_stack}); + store.register_late_pass(move || box vec::UselessVec{too_large_for_stack}); + store.register_late_pass(|| box panic_unimplemented::PanicUnimplemented); + store.register_late_pass(|| box strings::StringLitAsBytes); + store.register_late_pass(|| box derive::Derive); + store.register_late_pass(|| box get_last_with_len::GetLastWithLen); + store.register_late_pass(|| box drop_forget_ref::DropForgetRef); + store.register_late_pass(|| box empty_enum::EmptyEnum); + store.register_late_pass(|| box absurd_extreme_comparisons::AbsurdExtremeComparisons); + store.register_late_pass(|| box invalid_upcast_comparisons::InvalidUpcastComparisons); + store.register_late_pass(|| box regex::Regex::default()); + store.register_late_pass(|| box copies::CopyAndPaste); + store.register_late_pass(|| box copy_iterator::CopyIterator); + store.register_late_pass(|| box format::UselessFormat); + store.register_late_pass(|| box swap::Swap); + store.register_late_pass(|| box overflow_check_conditional::OverflowCheckConditional); + store.register_late_pass(|| box new_without_default::NewWithoutDefault::default()); + let blacklisted_names = conf.blacklisted_names.iter().cloned().collect::<FxHashSet<_>>(); + store.register_late_pass(move || box blacklisted_name::BlacklistedName::new(blacklisted_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 || box functions::Functions::new(too_many_arguments_threshold, too_many_lines_threshold)); + let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>(); + store.register_late_pass(move || box doc::DocMarkdown::new(doc_valid_idents.clone())); + store.register_late_pass(|| box neg_multiply::NegMultiply); + store.register_late_pass(|| box mem_discriminant::MemDiscriminant); + store.register_late_pass(|| box mem_forget::MemForget); + store.register_late_pass(|| box arithmetic::Arithmetic::default()); + store.register_late_pass(|| box assign_ops::AssignOps); + store.register_late_pass(|| box let_if_seq::LetIfSeq); + store.register_late_pass(|| box eval_order_dependence::EvalOrderDependence); + store.register_late_pass(|| box missing_doc::MissingDoc::new()); + store.register_late_pass(|| box missing_inline::MissingInline); + store.register_late_pass(move || box exhaustive_items::ExhaustiveItems); + store.register_late_pass(|| box if_let_some_result::OkIfLet); + store.register_late_pass(|| box partialeq_ne_impl::PartialEqNeImpl); + store.register_late_pass(|| box unused_io_amount::UnusedIoAmount); + let enum_variant_size_threshold = conf.enum_variant_size_threshold; + store.register_late_pass(move || box large_enum_variant::LargeEnumVariant::new(enum_variant_size_threshold)); + store.register_late_pass(|| box explicit_write::ExplicitWrite); + store.register_late_pass(|| box needless_pass_by_value::NeedlessPassByValue); + let pass_by_ref_or_value = pass_by_ref_or_value::PassByRefOrValue::new( + conf.trivial_copy_size_limit, + conf.pass_by_value_size_limit, + conf.avoid_breaking_exported_api, + &sess.target, + ); + store.register_late_pass(move || box pass_by_ref_or_value); + store.register_late_pass(|| box ref_option_ref::RefOptionRef); + store.register_late_pass(|| box try_err::TryErr); + store.register_late_pass(|| box bytecount::ByteCount); + store.register_late_pass(|| box infinite_iter::InfiniteIter); + store.register_late_pass(|| box inline_fn_without_body::InlineFnWithoutBody); + store.register_late_pass(|| box useless_conversion::UselessConversion::default()); + store.register_late_pass(|| box implicit_hasher::ImplicitHasher); + store.register_late_pass(|| box fallible_impl_from::FallibleImplFrom); + store.register_late_pass(|| box double_comparison::DoubleComparisons); + store.register_late_pass(|| box question_mark::QuestionMark); + store.register_early_pass(|| box suspicious_operation_groupings::SuspiciousOperationGroupings); + store.register_late_pass(|| box suspicious_trait_impl::SuspiciousImpl); + store.register_late_pass(|| box map_unit_fn::MapUnit); + store.register_late_pass(|| box inherent_impl::MultipleInherentImpl); + store.register_late_pass(|| box neg_cmp_op_on_partial_ord::NoNegCompOpForPartialOrd); + store.register_late_pass(|| box unwrap::Unwrap); + store.register_late_pass(|| box duration_subsec::DurationSubsec); + store.register_late_pass(|| box indexing_slicing::IndexingSlicing); + store.register_late_pass(|| box non_copy_const::NonCopyConst); + store.register_late_pass(|| box ptr_offset_with_cast::PtrOffsetWithCast); + store.register_late_pass(|| box redundant_clone::RedundantClone); + store.register_late_pass(|| box slow_vector_initialization::SlowVectorInit); + store.register_late_pass(|| box unnecessary_sort_by::UnnecessarySortBy); + store.register_late_pass(move || box unnecessary_wraps::UnnecessaryWraps::new(avoid_breaking_exported_api)); + store.register_late_pass(|| box assertions_on_constants::AssertionsOnConstants); + store.register_late_pass(|| box transmuting_null::TransmutingNull); + store.register_late_pass(|| box path_buf_push_overwrite::PathBufPushOverwrite); + store.register_late_pass(|| box integer_division::IntegerDivision); + store.register_late_pass(|| box inherent_to_string::InherentToString); + let max_trait_bounds = conf.max_trait_bounds; + store.register_late_pass(move || box trait_bounds::TraitBounds::new(max_trait_bounds)); + store.register_late_pass(|| box comparison_chain::ComparisonChain); + store.register_late_pass(|| box mut_key::MutableKeyType); + store.register_late_pass(|| box modulo_arithmetic::ModuloArithmetic); + store.register_early_pass(|| box reference::DerefAddrOf); + store.register_early_pass(|| box reference::RefInDeref); + store.register_early_pass(|| box double_parens::DoubleParens); + store.register_late_pass(|| box to_string_in_display::ToStringInDisplay::new()); + store.register_early_pass(|| box unsafe_removed_from_name::UnsafeNameRemoval); + store.register_early_pass(|| box if_not_else::IfNotElse); + store.register_early_pass(|| box else_if_without_else::ElseIfWithoutElse); + store.register_early_pass(|| box int_plus_one::IntPlusOne); + store.register_early_pass(|| box formatting::Formatting); + store.register_early_pass(|| box misc_early::MiscEarlyLints); + store.register_early_pass(|| box redundant_closure_call::RedundantClosureCall); + store.register_late_pass(|| box redundant_closure_call::RedundantClosureCall); + store.register_early_pass(|| box unused_unit::UnusedUnit); + store.register_late_pass(|| box returns::Return); + store.register_early_pass(|| box collapsible_if::CollapsibleIf); + store.register_early_pass(|| box items_after_statements::ItemsAfterStatements); + store.register_early_pass(|| box precedence::Precedence); + store.register_early_pass(|| box needless_continue::NeedlessContinue); + store.register_early_pass(|| box redundant_else::RedundantElse); + store.register_late_pass(|| box create_dir::CreateDir); + store.register_early_pass(|| box needless_arbitrary_self_type::NeedlessArbitrarySelfType); + let cargo_ignore_publish = conf.cargo_ignore_publish; + store.register_late_pass(move || box cargo_common_metadata::CargoCommonMetadata::new(cargo_ignore_publish)); + store.register_late_pass(|| box multiple_crate_versions::MultipleCrateVersions); + store.register_late_pass(|| box wildcard_dependencies::WildcardDependencies); + let literal_representation_lint_fraction_readability = conf.unreadable_literal_lint_fractions; + store.register_early_pass(move || box literal_representation::LiteralDigitGrouping::new(literal_representation_lint_fraction_readability)); + let literal_representation_threshold = conf.literal_representation_threshold; + store.register_early_pass(move || box literal_representation::DecimalLiteralRepresentation::new(literal_representation_threshold)); + let enum_variant_name_threshold = conf.enum_variant_name_threshold; + store.register_late_pass(move || box enum_variants::EnumVariantNames::new(enum_variant_name_threshold, avoid_breaking_exported_api)); + store.register_early_pass(|| box tabs_in_doc_comments::TabsInDocComments); + let upper_case_acronyms_aggressive = conf.upper_case_acronyms_aggressive; + store.register_late_pass(move || box upper_case_acronyms::UpperCaseAcronyms::new(avoid_breaking_exported_api, upper_case_acronyms_aggressive)); + store.register_late_pass(|| box default::Default::default()); + store.register_late_pass(|| box unused_self::UnusedSelf); + store.register_late_pass(|| box mutable_debug_assertion::DebugAssertWithMutCall); + store.register_late_pass(|| box exit::Exit); + store.register_late_pass(|| box to_digit_is_some::ToDigitIsSome); + let array_size_threshold = conf.array_size_threshold; + store.register_late_pass(move || box large_stack_arrays::LargeStackArrays::new(array_size_threshold)); + store.register_late_pass(move || box large_const_arrays::LargeConstArrays::new(array_size_threshold)); + store.register_late_pass(|| box floating_point_arithmetic::FloatingPointArithmetic); + store.register_early_pass(|| box as_conversions::AsConversions); + store.register_late_pass(|| box let_underscore::LetUnderscore); + store.register_late_pass(|| box atomic_ordering::AtomicOrdering); + store.register_early_pass(|| box single_component_path_imports::SingleComponentPathImports); + let max_fn_params_bools = conf.max_fn_params_bools; + let max_struct_bools = conf.max_struct_bools; + store.register_early_pass(move || box excessive_bools::ExcessiveBools::new(max_struct_bools, max_fn_params_bools)); + store.register_early_pass(|| box option_env_unwrap::OptionEnvUnwrap); + let warn_on_all_wildcard_imports = conf.warn_on_all_wildcard_imports; + store.register_late_pass(move || box wildcard_imports::WildcardImports::new(warn_on_all_wildcard_imports)); + store.register_late_pass(|| box verbose_file_reads::VerboseFileReads); + store.register_late_pass(|| box redundant_pub_crate::RedundantPubCrate::default()); + store.register_late_pass(|| box unnamed_address::UnnamedAddress); + store.register_late_pass(|| box dereference::Dereferencing::default()); + store.register_late_pass(|| box option_if_let_else::OptionIfLetElse); + store.register_late_pass(|| box future_not_send::FutureNotSend); + store.register_late_pass(|| box if_let_mutex::IfLetMutex); + store.register_late_pass(|| box mut_mutex_lock::MutMutexLock); + store.register_late_pass(|| box match_on_vec_items::MatchOnVecItems); + store.register_late_pass(|| box manual_async_fn::ManualAsyncFn); + store.register_late_pass(|| box vec_resize_to_zero::VecResizeToZero); + store.register_late_pass(|| box panic_in_result_fn::PanicInResultFn); + let single_char_binding_names_threshold = conf.single_char_binding_names_threshold; + store.register_early_pass(move || box non_expressive_names::NonExpressiveNames { + single_char_binding_names_threshold, + }); + store.register_late_pass(|| box macro_use::MacroUseImports::default()); + store.register_late_pass(|| box map_identity::MapIdentity); + store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch); + store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive); + store.register_late_pass(|| box repeat_once::RepeatOnce); + store.register_late_pass(|| box unwrap_in_result::UnwrapInResult); + store.register_late_pass(|| box self_assignment::SelfAssignment); + store.register_late_pass(|| box manual_unwrap_or::ManualUnwrapOr); + store.register_late_pass(|| box manual_ok_or::ManualOkOr); + store.register_late_pass(|| box float_equality_without_abs::FloatEqualityWithoutAbs); + store.register_late_pass(|| box semicolon_if_nothing_returned::SemicolonIfNothingReturned); + store.register_late_pass(|| box async_yields_async::AsyncYieldsAsync); + let disallowed_methods = conf.disallowed_methods.iter().cloned().collect::<FxHashSet<_>>(); + store.register_late_pass(move || box disallowed_method::DisallowedMethod::new(&disallowed_methods)); + store.register_early_pass(|| box asm_syntax::InlineAsmX86AttSyntax); + store.register_early_pass(|| box asm_syntax::InlineAsmX86IntelSyntax); + store.register_late_pass(|| box undropped_manually_drops::UndroppedManuallyDrops); + store.register_late_pass(|| box strings::StrToString); + store.register_late_pass(|| box strings::StringToString); + store.register_late_pass(|| box zero_sized_map_values::ZeroSizedMapValues); + store.register_late_pass(|| box vec_init_then_push::VecInitThenPush::default()); + store.register_late_pass(|| box case_sensitive_file_extension_comparisons::CaseSensitiveFileExtensionComparisons); + store.register_late_pass(|| box redundant_slicing::RedundantSlicing); + store.register_late_pass(|| box from_str_radix_10::FromStrRadix10); + store.register_late_pass(|| box manual_map::ManualMap); + store.register_late_pass(move || box if_then_some_else_none::IfThenSomeElseNone::new(msrv)); + store.register_early_pass(|| box bool_assert_comparison::BoolAssertComparison); + store.register_late_pass(|| box unused_async::UnusedAsync); + } #[rustfmt::skip] diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs index 116ad072837..5ae68ba5b2f 100644 --- a/src/tools/clippy/clippy_lints/src/lifetimes.rs +++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs @@ -205,7 +205,7 @@ fn could_use_elision<'tcx>( output_visitor.visit_ty(ty); } for lt in named_generics { - input_visitor.visit_generic_param(lt) + input_visitor.visit_generic_param(lt); } if input_visitor.abort() || output_visitor.abort() { @@ -463,7 +463,7 @@ impl<'tcx> Visitor<'tcx> for LifetimeChecker { // `'b` in `'a: 'b` is useless unless used elsewhere in // a non-lifetime bound if let GenericParamKind::Type { .. } = param.kind { - walk_generic_param(self, param) + walk_generic_param(self, param); } } fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs index e93b2e36b86..e0c5578bd60 100644 --- a/src/tools/clippy/clippy_lints/src/literal_representation.rs +++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs @@ -231,7 +231,7 @@ impl EarlyLintPass for LiteralDigitGrouping { } if let ExprKind::Lit(ref lit) = expr.kind { - self.check_lit(cx, lit) + self.check_lit(cx, lit); } } } @@ -294,7 +294,7 @@ impl LiteralDigitGrouping { } }; if should_warn { - warning_type.display(num_lit.format(), cx, lit.span) + warning_type.display(num_lit.format(), cx, lit.span); } } } @@ -424,7 +424,7 @@ impl EarlyLintPass for DecimalLiteralRepresentation { } if let ExprKind::Lit(ref lit) = expr.kind { - self.check_lit(cx, lit) + self.check_lit(cx, lit); } } } @@ -446,7 +446,7 @@ impl DecimalLiteralRepresentation { let hex = format!("{:#X}", val); let num_lit = NumericLiteral::new(&hex, num_lit.suffix, false); let _ = Self::do_lint(num_lit.integer).map_err(|warning_type| { - warning_type.display(num_lit.format(), cx, lit.span) + warning_type.display(num_lit.format(), cx, lit.span); }); } } diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs index ce02ad013be..f0327b5d777 100644 --- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs @@ -43,7 +43,7 @@ pub(super) fn check(cx: &LateContext<'_>, self_arg: &Expr<'_>, arg: &Expr<'_>, m "to write this more concisely, try", format!("&{}{}", muta, object), applicability, - ) + ); } /// Returns `true` if the type of expr is one that provides `IntoIterator` impls diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs index 1425d50f560..d07b5a93b67 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs @@ -88,10 +88,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { if let ty::BorrowKind::MutBorrow = bk { if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low { - self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)) + self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)); } if Some(id) == self.hir_id_high { - self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)) + self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)); } } } @@ -100,10 +100,10 @@ impl<'tcx> Delegate<'tcx> for MutatePairDelegate<'_, 'tcx> { fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, diag_expr_id: HirId) { if let PlaceBase::Local(id) = cmt.place.base { if Some(id) == self.hir_id_low { - self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)) + self.span_low = Some(self.cx.tcx.hir().span(diag_expr_id)); } if Some(id) == self.hir_id_high { - self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)) + self.span_high = Some(self.cx.tcx.hir().span(diag_expr_id)); } } } diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs index 9662a0b22a3..eb82c9c27c3 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_collect.rs @@ -1,16 +1,15 @@ use super::NEEDLESS_COLLECT; -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; -use clippy_utils::source::snippet; +use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; +use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::{is_type_diagnostic_item, match_type}; -use clippy_utils::{is_trait_method, path_to_local_id, paths}; +use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::{is_trait_method, path_to_local_id}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor}; use rustc_hir::{Block, Expr, ExprKind, GenericArg, GenericArgs, HirId, Local, Pat, PatKind, QPath, StmtKind, Ty}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; - use rustc_span::symbol::{sym, Ident}; use rustc_span::{MultiSpan, Span}; @@ -28,23 +27,37 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont if let Some(generic_args) = chain_method.args; if let Some(GenericArg::Type(ref ty)) = generic_args.args.get(0); if let Some(ty) = cx.typeck_results().node_type_opt(ty.hir_id); - if is_type_diagnostic_item(cx, ty, sym::vec_type) - || is_type_diagnostic_item(cx, ty, sym::vecdeque_type) - || match_type(cx, ty, &paths::BTREEMAP) - || is_type_diagnostic_item(cx, ty, sym::hashmap_type); - if let Some(sugg) = match &*method.ident.name.as_str() { - "len" => Some("count()".to_string()), - "is_empty" => Some("next().is_none()".to_string()), - "contains" => { - let contains_arg = snippet(cx, args[1].span, "??"); - let (arg, pred) = contains_arg - .strip_prefix('&') - .map_or(("&x", &*contains_arg), |s| ("x", s)); - Some(format!("any(|{}| x == {})", arg, pred)) - } - _ => None, - }; then { + let mut applicability = Applicability::MachineApplicable; + let is_empty_sugg = "next().is_none()".to_string(); + let method_name = &*method.ident.name.as_str(); + let sugg = if is_type_diagnostic_item(cx, ty, sym::vec_type) || + is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || + is_type_diagnostic_item(cx, ty, sym::LinkedList) || + is_type_diagnostic_item(cx, ty, sym::BinaryHeap) { + match method_name { + "len" => "count()".to_string(), + "is_empty" => is_empty_sugg, + "contains" => { + let contains_arg = snippet_with_applicability(cx, args[1].span, "??", &mut applicability); + let (arg, pred) = contains_arg + .strip_prefix('&') + .map_or(("&x", &*contains_arg), |s| ("x", s)); + format!("any(|{}| x == {})", arg, pred) + } + _ => return, + } + } + else if is_type_diagnostic_item(cx, ty, sym::BTreeMap) || + is_type_diagnostic_item(cx, ty, sym::hashmap_type) { + match method_name { + "is_empty" => is_empty_sugg, + _ => return, + } + } + else { + return; + }; span_lint_and_sugg( cx, NEEDLESS_COLLECT, @@ -52,7 +65,7 @@ fn check_needless_collect_direct_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCont NEEDLESS_COLLECT_MSG, "replace with", sugg, - Applicability::MachineApplicable, + applicability, ); } } @@ -86,7 +99,7 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo if is_type_diagnostic_item(cx, ty, sym::vec_type) || is_type_diagnostic_item(cx, ty, sym::vecdeque_type) || is_type_diagnostic_item(cx, ty, sym::BinaryHeap) || - match_type(cx, ty, &paths::LINKED_LIST); + is_type_diagnostic_item(cx, ty, sym::LinkedList); if let Some(iter_calls) = detect_iter_and_into_iters(block, *ident); if let [iter_call] = &*iter_calls; then { @@ -103,9 +116,10 @@ fn check_needless_collect_indirect_usage<'tcx>(expr: &'tcx Expr<'_>, cx: &LateCo // Suggest replacing iter_call with iter_replacement, and removing stmt let mut span = MultiSpan::from_span(collect_span); span.push_span_label(iter_call.span, "the iterator could be used here instead".into()); - span_lint_and_then( + span_lint_hir_and_then( cx, super::NEEDLESS_COLLECT, + init_expr.hir_id, span, NEEDLESS_COLLECT_MSG, |diag| { diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs index cb2c83e9029..0f6cd5de761 100644 --- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs +++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs @@ -35,7 +35,7 @@ pub(super) fn check<'tcx>( "try using vec![{};SIZE] or {}.resize(NEW_SIZE, {})", item_str, vec_str, item_str ), - ) + ); } if !matches!(pat.kind, PatKind::Wild) { diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs index 4db6644b9d7..2f7360210ba 100644 --- a/src/tools/clippy/clippy_lints/src/loops/utils.rs +++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs @@ -80,10 +80,10 @@ impl<'a, 'tcx> Visitor<'tcx> for IncrementVisitor<'a, 'tcx> { } }, ExprKind::Assign(lhs, _, _) if lhs.hir_id == expr.hir_id => { - *state = IncrementVisitorVarState::DontWarn + *state = IncrementVisitorVarState::DontWarn; }, ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => { - *state = IncrementVisitorVarState::DontWarn + *state = IncrementVisitorVarState::DontWarn; }, _ => (), } @@ -207,7 +207,7 @@ impl<'a, 'tcx> Visitor<'tcx> for InitializeVisitor<'a, 'tcx> { } }, ExprKind::AddrOf(BorrowKind::Ref, mutability, _) if mutability == Mutability::Mut => { - self.state = InitializeVisitorState::DontWarn + self.state = InitializeVisitorState::DontWarn; }, _ => (), } @@ -292,7 +292,7 @@ impl<'tcx> Visitor<'tcx> for LoopNestVisitor { return; } } - walk_pat(self, pat) + walk_pat(self, pat); } fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { diff --git a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs index 55404b87ec9..5f9ebad25e8 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_immutable_condition.rs @@ -1,5 +1,5 @@ use super::WHILE_IMMUTABLE_CONDITION; -use crate::consts::constant; +use clippy_utils::consts::constant; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::usage::mutated_variables; use if_chain::if_chain; diff --git a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs index 82715d9bafa..63560047578 100644 --- a/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs +++ b/src/tools/clippy/clippy_lints/src/loops/while_let_on_iterator.rs @@ -1,170 +1,347 @@ -use super::utils::{LoopNestVisitor, Nesting}; use super::WHILE_LET_ON_ITERATOR; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_applicability; -use clippy_utils::ty::implements_trait; -use clippy_utils::usage::mutated_variables; -use clippy_utils::{ - get_enclosing_block, is_refutable, is_trait_method, last_path_segment, path_to_local, path_to_local_id, -}; +use clippy_utils::{get_enclosing_loop, is_refutable, is_trait_method, match_def_path, paths, visitors::is_res_used}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::intravisit::{walk_block, walk_expr, NestedVisitorMap, Visitor}; -use rustc_hir::{Expr, ExprKind, HirId, MatchSource, Node, PatKind}; +use rustc_hir::intravisit::{walk_expr, ErasedMap, NestedVisitorMap, Visitor}; +use rustc_hir::{def::Res, Expr, ExprKind, HirId, Local, MatchSource, Node, PatKind, QPath, UnOp}; use rustc_lint::LateContext; -use rustc_middle::hir::map::Map; -use rustc_span::symbol::sym; +use rustc_span::{symbol::sym, Span, Symbol}; pub(super) fn check(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - if let ExprKind::Match(match_expr, arms, MatchSource::WhileLetDesugar) = expr.kind { - let pat = &arms[0].pat.kind; - if let (&PatKind::TupleStruct(ref qpath, pat_args, _), &ExprKind::MethodCall(method_path, _, method_args, _)) = - (pat, &match_expr.kind) - { - let iter_expr = &method_args[0]; - - // Don't lint when the iterator is recreated on every iteration - if_chain! { - if let ExprKind::MethodCall(..) | ExprKind::Call(..) = iter_expr.kind; - if let Some(iter_def_id) = cx.tcx.get_diagnostic_item(sym::Iterator); - if implements_trait(cx, cx.typeck_results().expr_ty(iter_expr), iter_def_id, &[]); - then { - return; - } - } + let (scrutinee_expr, iter_expr, some_pat, loop_expr) = if_chain! { + if let ExprKind::Match(scrutinee_expr, [arm, _], MatchSource::WhileLetDesugar) = expr.kind; + // check for `Some(..)` pattern + if let PatKind::TupleStruct(QPath::Resolved(None, pat_path), some_pat, _) = arm.pat.kind; + if let Res::Def(_, pat_did) = pat_path.res; + if match_def_path(cx, pat_did, &paths::OPTION_SOME); + // check for call to `Iterator::next` + if let ExprKind::MethodCall(method_name, _, [iter_expr], _) = scrutinee_expr.kind; + if method_name.ident.name == sym::next; + if is_trait_method(cx, scrutinee_expr, sym::Iterator); + if let Some(iter_expr) = try_parse_iter_expr(cx, iter_expr); + // get the loop containing the match expression + if let Some((_, Node::Expr(loop_expr))) = cx.tcx.hir().parent_iter(expr.hir_id).nth(1); + if !uses_iter(cx, &iter_expr, arm.body); + then { + (scrutinee_expr, iter_expr, some_pat, loop_expr) + } else { + return; + } + }; - let lhs_constructor = last_path_segment(qpath); - if method_path.ident.name == sym::next - && is_trait_method(cx, match_expr, sym::Iterator) - && lhs_constructor.ident.name == sym::Some - && (pat_args.is_empty() - || !is_refutable(cx, pat_args[0]) - && !is_used_inside(cx, iter_expr, arms[0].body) - && !is_iterator_used_after_while_let(cx, iter_expr) - && !is_nested(cx, expr, &method_args[0])) - { - let mut applicability = Applicability::MachineApplicable; - let iterator = snippet_with_applicability(cx, method_args[0].span, "_", &mut applicability); - let loop_var = if pat_args.is_empty() { - "_".to_string() - } else { - snippet_with_applicability(cx, pat_args[0].span, "_", &mut applicability).into_owned() - }; - span_lint_and_sugg( - cx, - WHILE_LET_ON_ITERATOR, - expr.span.with_hi(match_expr.span.hi()), - "this loop could be written as a `for` loop", - "try", - format!("for {} in {}", loop_var, iterator), - applicability, - ); - } + let mut applicability = Applicability::MachineApplicable; + let loop_var = if let Some(some_pat) = some_pat.first() { + if is_refutable(cx, some_pat) { + // Refutable patterns don't work with for loops. + return; } - } -} + snippet_with_applicability(cx, some_pat.span, "..", &mut applicability) + } else { + "_".into() + }; -fn is_used_inside<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, container: &'tcx Expr<'_>) -> bool { - let def_id = match path_to_local(expr) { - Some(id) => id, - None => return false, + // If the iterator is a field or the iterator is accessed after the loop is complete it needs to be + // borrowed mutably. TODO: If the struct can be partially moved from and the struct isn't used + // afterwards a mutable borrow of a field isn't necessary. + let ref_mut = if !iter_expr.fields.is_empty() || needs_mutable_borrow(cx, &iter_expr, loop_expr) { + "&mut " + } else { + "" }; - if let Some(used_mutably) = mutated_variables(container, cx) { - if used_mutably.contains(&def_id) { - return true; + + let iterator = snippet_with_applicability(cx, iter_expr.span, "_", &mut applicability); + span_lint_and_sugg( + cx, + WHILE_LET_ON_ITERATOR, + expr.span.with_hi(scrutinee_expr.span.hi()), + "this loop could be written as a `for` loop", + "try", + format!("for {} in {}{}", loop_var, ref_mut, iterator), + applicability, + ); +} + +#[derive(Debug)] +struct IterExpr { + /// The span of the whole expression, not just the path and fields stored here. + span: Span, + /// The fields used, in order of child to parent. + fields: Vec<Symbol>, + /// The path being used. + path: Res, +} +/// Parses any expression to find out which field of which variable is used. Will return `None` if +/// the expression might have side effects. +fn try_parse_iter_expr(cx: &LateContext<'_>, mut e: &Expr<'_>) -> Option<IterExpr> { + let span = e.span; + let mut fields = Vec::new(); + loop { + match e.kind { + ExprKind::Path(ref path) => { + break Some(IterExpr { + span, + fields, + path: cx.qpath_res(path, e.hir_id), + }); + }, + ExprKind::Field(base, name) => { + fields.push(name.name); + e = base; + }, + // Dereferencing a pointer has no side effects and doesn't affect which field is being used. + ExprKind::Unary(UnOp::Deref, base) if cx.typeck_results().expr_ty(base).is_ref() => e = base, + + // Shouldn't have side effects, but there's no way to trace which field is used. So forget which fields have + // already been seen. + ExprKind::Index(base, idx) if !idx.can_have_side_effects() => { + fields.clear(); + e = base; + }, + ExprKind::Unary(UnOp::Deref, base) => { + fields.clear(); + e = base; + }, + + // No effect and doesn't affect which field is being used. + ExprKind::DropTemps(base) | ExprKind::AddrOf(_, _, base) | ExprKind::Type(base, _) => e = base, + _ => break None, } } - false } -fn is_iterator_used_after_while_let<'tcx>(cx: &LateContext<'tcx>, iter_expr: &'tcx Expr<'_>) -> bool { - let def_id = match path_to_local(iter_expr) { - Some(id) => id, - None => return false, - }; - let mut visitor = VarUsedAfterLoopVisitor { - def_id, - iter_expr_id: iter_expr.hir_id, - past_while_let: false, - var_used_after_while_let: false, - }; - if let Some(enclosing_block) = get_enclosing_block(cx, def_id) { - walk_block(&mut visitor, enclosing_block); +fn is_expr_same_field(cx: &LateContext<'_>, mut e: &Expr<'_>, mut fields: &[Symbol], path_res: Res) -> bool { + loop { + match (&e.kind, fields) { + (&ExprKind::Field(base, name), [head_field, tail_fields @ ..]) if name.name == *head_field => { + e = base; + fields = tail_fields; + }, + (ExprKind::Path(path), []) => { + break cx.qpath_res(path, e.hir_id) == path_res; + }, + (&(ExprKind::DropTemps(base) | ExprKind::AddrOf(_, _, base) | ExprKind::Type(base, _)), _) => e = base, + _ => break false, + } } - visitor.var_used_after_while_let } -fn is_nested(cx: &LateContext<'_>, match_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool { - if_chain! { - if let Some(loop_block) = get_enclosing_block(cx, match_expr.hir_id); - let parent_node = cx.tcx.hir().get_parent_node(loop_block.hir_id); - if let Some(Node::Expr(loop_expr)) = cx.tcx.hir().find(parent_node); - then { - return is_loop_nested(cx, loop_expr, iter_expr) - } +/// Checks if the given expression is the same field as, is a child of, or is the parent of the +/// given field. Used to check if the expression can be used while the given field is borrowed +/// mutably. e.g. if checking for `x.y`, then `x.y`, `x.y.z`, and `x` will all return true, but +/// `x.z`, and `y` will return false. +fn is_expr_same_child_or_parent_field(cx: &LateContext<'_>, expr: &Expr<'_>, fields: &[Symbol], path_res: Res) -> bool { + match expr.kind { + ExprKind::Field(base, name) => { + if let Some((head_field, tail_fields)) = fields.split_first() { + if name.name == *head_field && is_expr_same_field(cx, base, fields, path_res) { + return true; + } + // Check if the expression is a parent field + let mut fields_iter = tail_fields.iter(); + while let Some(field) = fields_iter.next() { + if *field == name.name && is_expr_same_field(cx, base, fields_iter.as_slice(), path_res) { + return true; + } + } + } + + // Check if the expression is a child field. + let mut e = base; + loop { + match e.kind { + ExprKind::Field(..) if is_expr_same_field(cx, e, fields, path_res) => break true, + ExprKind::Field(base, _) | ExprKind::DropTemps(base) | ExprKind::Type(base, _) => e = base, + ExprKind::Path(ref path) if fields.is_empty() => { + break cx.qpath_res(path, e.hir_id) == path_res; + }, + _ => break false, + } + } + }, + // If the path matches, this is either an exact match, or the expression is a parent of the field. + ExprKind::Path(ref path) => cx.qpath_res(path, expr.hir_id) == path_res, + ExprKind::DropTemps(base) | ExprKind::Type(base, _) | ExprKind::AddrOf(_, _, base) => { + is_expr_same_child_or_parent_field(cx, base, fields, path_res) + }, + _ => false, } - false } -fn is_loop_nested(cx: &LateContext<'_>, loop_expr: &Expr<'_>, iter_expr: &Expr<'_>) -> bool { - let mut id = loop_expr.hir_id; - let iter_id = if let Some(id) = path_to_local(iter_expr) { - id - } else { - return true; +/// Strips off all field and path expressions. This will return true if a field or path has been +/// skipped. Used to skip them after failing to check for equality. +fn skip_fields_and_path(expr: &'tcx Expr<'_>) -> (Option<&'tcx Expr<'tcx>>, bool) { + let mut e = expr; + let e = loop { + match e.kind { + ExprKind::Field(base, _) | ExprKind::DropTemps(base) | ExprKind::Type(base, _) => e = base, + ExprKind::Path(_) => return (None, true), + _ => break e, + } }; - loop { - let parent = cx.tcx.hir().get_parent_node(id); - if parent == id { - return false; + (Some(e), e.hir_id != expr.hir_id) +} + +/// Checks if the given expression uses the iterator. +fn uses_iter(cx: &LateContext<'tcx>, iter_expr: &IterExpr, container: &'tcx Expr<'_>) -> bool { + struct V<'a, 'b, 'tcx> { + cx: &'a LateContext<'tcx>, + iter_expr: &'b IterExpr, + uses_iter: bool, + } + impl Visitor<'tcx> for V<'_, '_, 'tcx> { + type Map = ErasedMap<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None } - match cx.tcx.hir().find(parent) { - Some(Node::Expr(expr)) => { - if let ExprKind::Loop(..) = expr.kind { - return true; - }; - }, - Some(Node::Block(block)) => { - let mut block_visitor = LoopNestVisitor { - hir_id: id, - iterator: iter_id, - nesting: Nesting::Unknown, - }; - walk_block(&mut block_visitor, block); - if block_visitor.nesting == Nesting::RuledOut { - return false; + + fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + if self.uses_iter { + // return + } else if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) { + self.uses_iter = true; + } else if let (e, true) = skip_fields_and_path(e) { + if let Some(e) = e { + self.visit_expr(e); } - }, - Some(Node::Stmt(_)) => (), - _ => { - return false; - }, + } else if let ExprKind::Closure(_, _, id, _, _) = e.kind { + if is_res_used(self.cx, self.iter_expr.path, id) { + self.uses_iter = true; + } + } else { + walk_expr(self, e); + } } - id = parent; } -} -struct VarUsedAfterLoopVisitor { - def_id: HirId, - iter_expr_id: HirId, - past_while_let: bool, - var_used_after_while_let: bool, + let mut v = V { + cx, + iter_expr, + uses_iter: false, + }; + v.visit_expr(container); + v.uses_iter } -impl<'tcx> Visitor<'tcx> for VarUsedAfterLoopVisitor { - type Map = Map<'tcx>; +#[allow(clippy::too_many_lines)] +fn needs_mutable_borrow(cx: &LateContext<'tcx>, iter_expr: &IterExpr, loop_expr: &'tcx Expr<'_>) -> bool { + struct AfterLoopVisitor<'a, 'b, 'tcx> { + cx: &'a LateContext<'tcx>, + iter_expr: &'b IterExpr, + loop_id: HirId, + after_loop: bool, + used_iter: bool, + } + impl Visitor<'tcx> for AfterLoopVisitor<'_, '_, 'tcx> { + type Map = ErasedMap<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None + } - fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { - if self.past_while_let { - if path_to_local_id(expr, self.def_id) { - self.var_used_after_while_let = true; + fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + if self.used_iter { + return; + } + if self.after_loop { + if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) { + self.used_iter = true; + } else if let (e, true) = skip_fields_and_path(e) { + if let Some(e) = e { + self.visit_expr(e); + } + } else if let ExprKind::Closure(_, _, id, _, _) = e.kind { + self.used_iter = is_res_used(self.cx, self.iter_expr.path, id); + } else { + walk_expr(self, e); + } + } else if self.loop_id == e.hir_id { + self.after_loop = true; + } else { + walk_expr(self, e); + } + } + } + + struct NestedLoopVisitor<'a, 'b, 'tcx> { + cx: &'a LateContext<'tcx>, + iter_expr: &'b IterExpr, + local_id: HirId, + loop_id: HirId, + after_loop: bool, + found_local: bool, + used_after: bool, + } + impl Visitor<'tcx> for NestedLoopVisitor<'a, 'b, 'tcx> { + type Map = ErasedMap<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::None + } + + fn visit_local(&mut self, l: &'tcx Local<'_>) { + if !self.after_loop { + l.pat.each_binding_or_first(&mut |_, id, _, _| { + if id == self.local_id { + self.found_local = true; + } + }); + } + if let Some(e) = l.init { + self.visit_expr(e); + } + } + + fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + if self.used_after { + return; + } + if self.after_loop { + if is_expr_same_child_or_parent_field(self.cx, e, &self.iter_expr.fields, self.iter_expr.path) { + self.used_after = true; + } else if let (e, true) = skip_fields_and_path(e) { + if let Some(e) = e { + self.visit_expr(e); + } + } else if let ExprKind::Closure(_, _, id, _, _) = e.kind { + self.used_after = is_res_used(self.cx, self.iter_expr.path, id); + } else { + walk_expr(self, e); + } + } else if e.hir_id == self.loop_id { + self.after_loop = true; + } else { + walk_expr(self, e); } - } else if self.iter_expr_id == expr.hir_id { - self.past_while_let = true; } - walk_expr(self, expr); } - fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { - NestedVisitorMap::None + + if let Some(e) = get_enclosing_loop(cx.tcx, loop_expr) { + // The iterator expression will be used on the next iteration unless it is declared within the outer + // loop. + let local_id = match iter_expr.path { + Res::Local(id) => id, + _ => return true, + }; + let mut v = NestedLoopVisitor { + cx, + iter_expr, + local_id, + loop_id: loop_expr.hir_id, + after_loop: false, + found_local: false, + used_after: false, + }; + v.visit_expr(e); + v.used_after || !v.found_local + } else { + let mut v = AfterLoopVisitor { + cx, + iter_expr, + loop_id: loop_expr.hir_id, + after_loop: false, + used_iter: false, + }; + v.visit_expr(&cx.tcx.hir().body(cx.enclosing_body.unwrap()).value); + v.used_iter } } diff --git a/src/tools/clippy/clippy_lints/src/macro_use.rs b/src/tools/clippy/clippy_lints/src/macro_use.rs index 314bf11e2d6..66479ae264e 100644 --- a/src/tools/clippy/clippy_lints/src/macro_use.rs +++ b/src/tools/clippy/clippy_lints/src/macro_use.rs @@ -47,7 +47,12 @@ pub struct MacroRefData { impl MacroRefData { pub fn new(name: String, callee: Span, cx: &LateContext<'_>) -> Self { - let mut path = cx.sess().source_map().span_to_filename(callee).prefer_local().to_string(); + let mut path = cx + .sess() + .source_map() + .span_to_filename(callee) + .prefer_local() + .to_string(); // std lib paths are <::std::module::file type> // so remove brackets, space and type. @@ -96,7 +101,8 @@ impl MacroUseImports { let name = snippet(cx, cx.sess().source_map().span_until_char(call_site, '!'), "_"); if let Some(callee) = span.source_callee() { if !self.collected.contains(&call_site) { - self.mac_refs.push(MacroRefData::new(name.to_string(), callee.def_site, cx)); + self.mac_refs + .push(MacroRefData::new(name.to_string(), callee.def_site, cx)); self.collected.insert(call_site); } } @@ -174,7 +180,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { .push((*item).to_string()); check_dup.push((*item).to_string()); } - } + }, [root, rest @ ..] => { if rest.iter().all(|item| !check_dup.contains(&(*item).to_string())) { let filtered = rest @@ -198,7 +204,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { .push(rest.join("::")); check_dup.extend(rest.iter().map(ToString::to_string)); } - } + }, } } } @@ -206,9 +212,9 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { let mut suggestions = vec![]; for ((root, span), path) in used { if path.len() == 1 { - suggestions.push((span, format!("{}::{}", root, path[0]))) + suggestions.push((span, format!("{}::{}", root, path[0]))); } else { - suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")))) + suggestions.push((span, format!("{}::{{{}}}", root, path.join(", ")))); } } @@ -225,7 +231,7 @@ impl<'tcx> LateLintPass<'tcx> for MacroUseImports { "remove the attribute and import the macro directly, try", help, Applicability::MaybeIncorrect, - ) + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 23428524dee..61b5fe81fa9 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::usage::mutated_variables; @@ -123,7 +123,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualStrip { kind_word, snippet(cx, pattern.span, "..")))] .into_iter().chain(strippings.into_iter().map(|span| (span, "<stripped>".into()))), - ) + ); }); } } diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs index 520162559e5..18038dd7819 100644 --- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs +++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or.rs @@ -1,4 +1,4 @@ -use crate::consts::constant_simple; +use clippy_utils::consts::constant_simple; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::{indent_of, reindent_multiline, snippet_opt}; use clippy_utils::ty::is_type_diagnostic_item; @@ -53,21 +53,6 @@ impl LateLintPass<'_> for ManualUnwrapOr { } } -#[derive(Copy, Clone)] -enum Case { - Option, - Result, -} - -impl Case { - fn unwrap_fn_path(&self) -> &str { - match self { - Case::Option => "Option::unwrap_or", - Case::Result => "Result::unwrap_or", - } - } -} - fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<&'a Arm<'a>> { if_chain! { @@ -86,6 +71,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk); if let PatKind::Binding(_, binding_hir_id, ..) = unwrap_pat.kind; if path_to_local_id(unwrap_arm.body, binding_hir_id); + if cx.typeck_results().expr_adjustments(unwrap_arm.body).is_empty(); if !contains_return_break_continue_macro(or_arm.body); then { Some(or_arm) @@ -98,10 +84,10 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { if_chain! { if let ExprKind::Match(scrutinee, match_arms, _) = expr.kind; let ty = cx.typeck_results().expr_ty(scrutinee); - if let Some(case) = if is_type_diagnostic_item(cx, ty, sym::option_type) { - Some(Case::Option) + if let Some(ty_name) = if is_type_diagnostic_item(cx, ty, sym::option_type) { + Some("Option") } else if is_type_diagnostic_item(cx, ty, sym::result_type) { - Some(Case::Result) + Some("Result") } else { None }; @@ -124,7 +110,7 @@ fn lint_manual_unwrap_or<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { span_lint_and_sugg( cx, MANUAL_UNWRAP_OR, expr.span, - &format!("this pattern reimplements `{}`", case.unwrap_fn_path()), + &format!("this pattern reimplements `{}::unwrap_or`", ty_name), "replace with", format!( "{}.unwrap_or({})", diff --git a/src/tools/clippy/clippy_lints/src/map_clone.rs b/src/tools/clippy/clippy_lints/src/map_clone.rs index 99c35ae3bbf..e1f80ab025c 100644 --- a/src/tools/clippy/clippy_lints/src/map_clone.rs +++ b/src/tools/clippy/clippy_lints/src/map_clone.rs @@ -125,7 +125,7 @@ fn lint_needless_cloning(cx: &LateContext<'_>, root: Span, receiver: Span) { "remove the `map` call", String::new(), Applicability::MachineApplicable, - ) + ); } fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { @@ -142,7 +142,7 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { snippet_with_applicability(cx, root, "..", &mut applicability) ), applicability, - ) + ); } else { span_lint_and_sugg( cx, @@ -155,6 +155,6 @@ fn lint(cx: &LateContext<'_>, replace: Span, root: Span, copied: bool) { snippet_with_applicability(cx, root, "..", &mut applicability) ), applicability, - ) + ); } } diff --git a/src/tools/clippy/clippy_lints/src/matches.rs b/src/tools/clippy/clippy_lints/src/matches.rs index a70e8b26087..cd3e3b97928 100644 --- a/src/tools/clippy/clippy_lints/src/matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, miri_to_const, Constant}; +use clippy_utils::consts::{constant, miri_to_const, Constant}; use clippy_utils::diagnostics::{ multispan_sugg, span_lint_and_help, span_lint_and_note, span_lint_and_sugg, span_lint_and_then, }; @@ -1144,7 +1144,7 @@ fn check_wild_enum_match(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) "try this", suggestions.join(" | "), Applicability::MaybeIncorrect, - ) + ); }, }; } @@ -1242,7 +1242,7 @@ fn check_match_as_ref(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], exp cast, ), applicability, - ) + ); } } } @@ -1478,15 +1478,34 @@ fn check_match_single_binding<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[A ); }, PatKind::Wild => { - span_lint_and_sugg( - cx, - MATCH_SINGLE_BINDING, - expr.span, - "this match could be replaced by its body itself", - "consider using the match body instead", - snippet_body, - Applicability::MachineApplicable, - ); + if ex.can_have_side_effects() { + let indent = " ".repeat(indent_of(cx, expr.span).unwrap_or(0)); + let sugg = format!( + "{};\n{}{}", + snippet_with_applicability(cx, ex.span, "..", &mut applicability), + indent, + snippet_body + ); + span_lint_and_sugg( + cx, + MATCH_SINGLE_BINDING, + expr.span, + "this match could be replaced by its scrutinee and body", + "consider using the scrutinee and body instead", + sugg, + applicability, + ); + } else { + span_lint_and_sugg( + cx, + MATCH_SINGLE_BINDING, + expr.span, + "this match could be replaced by its body itself", + "consider using the match body instead", + snippet_body, + Applicability::MachineApplicable, + ); + } }, _ => (), } @@ -1728,7 +1747,7 @@ mod redundant_pattern_match { match match_source { MatchSource::Normal => find_sugg_for_match(cx, expr, op, arms), MatchSource::IfLetDesugar { contains_else_clause } => { - find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause) + find_sugg_for_if_let(cx, expr, op, &arms[0], "if", *contains_else_clause); }, MatchSource::WhileLetDesugar => find_sugg_for_if_let(cx, expr, op, &arms[0], "while", false), _ => {}, @@ -1857,7 +1876,7 @@ mod redundant_pattern_match { { self.res = true; } else { - self.visit_expr(self_arg) + self.visit_expr(self_arg); } } args.iter().for_each(|arg| self.visit_expr(arg)); diff --git a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs index a735c616f6e..aca96e06ef2 100644 --- a/src/tools/clippy/clippy_lints/src/mem_discriminant.rs +++ b/src/tools/clippy/clippy_lints/src/mem_discriminant.rs @@ -7,7 +7,6 @@ use rustc_errors::Applicability; use rustc_hir::{BorrowKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use std::iter; declare_clippy_lint! { /// **What it does:** Checks for calls of `mem::discriminant()` on a non-enum type. @@ -67,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for MemDiscriminant { } } - let derefs: String = iter::repeat('*').take(derefs_needed).collect(); + let derefs = "*".repeat(derefs_needed); diag.span_suggestion( param.span, "try dereferencing", diff --git a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs index 287bff886bf..da428a7b487 100644 --- a/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs +++ b/src/tools/clippy/clippy_lints/src/methods/bind_instead_of_map.rs @@ -135,7 +135,7 @@ pub(crate) trait BindInsteadOfMap { .into_iter() .map(|(span1, span2)| (span1, snippet(cx, span2, "_").into())), ), - ) + ); }); true } 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 ce2e8fa8b10..1a32af5dc7a 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 @@ -8,7 +8,6 @@ use rustc_hir::{BindingAnnotation, Expr, ExprKind, MatchSource, Node, PatKind}; use rustc_lint::LateContext; use rustc_middle::ty::{self, adjustment::Adjust}; use rustc_span::symbol::{sym, Symbol}; -use std::iter; use super::CLONE_DOUBLE_REF; use super::CLONE_ON_COPY; @@ -54,8 +53,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, method_name: Symbol, ty = inner; n += 1; } - let refs: String = iter::repeat('&').take(n + 1).collect(); - let derefs: String = iter::repeat('*').take(n).collect(); + let refs = "&".repeat(n + 1); + let derefs = "*".repeat(n); let explicit = format!("<{}{}>::clone({})", refs, ty, snip); diag.span_suggestion( expr.span, diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs index ecec6da3aa0..f5b4b6bf8ea 100644 --- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs +++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs @@ -41,5 +41,5 @@ pub fn check(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, span: Span, "try", "copied".into(), Applicability::MachineApplicable, - ) + ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs index 12d560653ed..32d40d97bf4 100644 --- a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs +++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs @@ -30,5 +30,5 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, arg "try", "filter_map".into(), Applicability::MachineApplicable, - ) + ); } diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs index 28d0e8cd4ae..b4188d9ed30 100644 --- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs @@ -37,6 +37,10 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Exp } fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) -> String { + fn strip_angle_brackets(s: &str) -> Option<&str> { + s.strip_prefix('<')?.strip_suffix('>') + } + let call_site = expr.span.source_callsite(); if_chain! { if let Ok(snippet) = cx.sess().source_map().span_to_snippet(call_site); @@ -44,23 +48,32 @@ fn extract_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>, ty: Ty<'tcx>) - if let Some((_, elements)) = snippet_split.split_last(); then { - // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`) - if let Some(type_specifier) = snippet_split.iter().find(|e| e.starts_with('<') && e.ends_with('>')) { - // remove the type specifier from the path elements - let without_ts = elements.iter().filter_map(|e| { - if e == type_specifier { None } else { Some((*e).to_string()) } - }).collect::<Vec<_>>(); - // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`) - format!("{}{}", without_ts.join("::"), type_specifier) - } else { - // type is not explicitly specified so wildcards are needed - // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` - let ty_str = ty.to_string(); - let start = ty_str.find('<').unwrap_or(0); - let end = ty_str.find('>').unwrap_or_else(|| ty_str.len()); - let nb_wildcard = ty_str[start..end].split(',').count(); - let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); - format!("{}<{}>", elements.join("::"), wildcards) + if_chain! { + if let [type_specifier, _] = snippet_split.as_slice(); + if let Some(type_specifier) = strip_angle_brackets(type_specifier); + if let Some((type_specifier, ..)) = type_specifier.split_once(" as "); + then { + type_specifier.to_string() + } else { + // is there a type specifier? (i.e.: like `<u32>` in `collections::BTreeSet::<u32>::`) + if let Some(type_specifier) = snippet_split.iter().find(|e| strip_angle_brackets(e).is_some()) { + // remove the type specifier from the path elements + let without_ts = elements.iter().filter_map(|e| { + if e == type_specifier { None } else { Some((*e).to_string()) } + }).collect::<Vec<_>>(); + // join and add the type specifier at the end (i.e.: `collections::BTreeSet<u32>`) + format!("{}{}", without_ts.join("::"), type_specifier) + } else { + // type is not explicitly specified so wildcards are needed + // i.e.: 2 wildcards in `std::collections::BTreeMap<&i32, &char>` + let ty_str = ty.to_string(); + let start = ty_str.find('<').unwrap_or(0); + let end = ty_str.find('>').unwrap_or_else(|| ty_str.len()); + let nb_wildcard = ty_str[start..end].split(',').count(); + let wildcards = format!("_{}", ", _".repeat(nb_wildcard - 1)); + format!("{}<{}>", elements.join("::"), wildcards) + } + } } } else { ty.to_string() diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs index 52d7c15332e..68d906c3ea3 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::is_trait_method; use clippy_utils::source::snippet_with_applicability; diff --git a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs index 06b12998b1a..64c09214a76 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::is_trait_method; use rustc_hir as hir; diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs new file mode 100644 index 00000000000..919e2628c52 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs @@ -0,0 +1,99 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::{snippet_with_applicability, snippet_with_context}; +use clippy_utils::sugg::Sugg; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item, match_type}; +use clippy_utils::{is_expr_path_def_path, paths}; +use if_chain::if_chain; +use rustc_ast::LitKind; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, LangItem}; +use rustc_lint::LateContext; +use rustc_middle::ty::{self, Ty, TyS}; +use rustc_span::symbol::sym; +use std::borrow::Cow; + +use super::MANUAL_STR_REPEAT; + +enum RepeatKind { + String, + Char(char), +} + +fn get_ty_param(ty: Ty<'_>) -> Option<Ty<'_>> { + if let ty::Adt(_, subs) = ty.kind() { + subs.types().next() + } else { + None + } +} + +fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> { + if let ExprKind::Lit(lit) = &e.kind { + match lit.node { + LitKind::Str(..) => Some(RepeatKind::String), + LitKind::Char(c) => Some(RepeatKind::Char(c)), + _ => None, + } + } else { + let ty = cx.typeck_results().expr_ty(e); + if is_type_diagnostic_item(cx, ty, sym::string_type) + || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, TyS::is_str)) + || (match_type(cx, ty, &paths::COW) && get_ty_param(ty).map_or(false, TyS::is_str)) + { + Some(RepeatKind::String) + } else { + let ty = ty.peel_refs(); + (ty.is_str() || is_type_diagnostic_item(cx, ty, sym::string_type)).then(|| RepeatKind::String) + } + } +} + +pub(super) fn check( + cx: &LateContext<'_>, + collect_expr: &Expr<'_>, + take_expr: &Expr<'_>, + take_self_arg: &Expr<'_>, + take_arg: &Expr<'_>, +) { + if_chain! { + if let ExprKind::Call(repeat_fn, [repeat_arg]) = take_self_arg.kind; + if is_expr_path_def_path(cx, repeat_fn, &paths::ITER_REPEAT); + if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(collect_expr), sym::string_type); + if let Some(collect_id) = cx.typeck_results().type_dependent_def_id(collect_expr.hir_id); + if let Some(take_id) = cx.typeck_results().type_dependent_def_id(take_expr.hir_id); + if let Some(iter_trait_id) = cx.tcx.get_diagnostic_item(sym::Iterator); + if cx.tcx.trait_of_item(collect_id) == Some(iter_trait_id); + if cx.tcx.trait_of_item(take_id) == Some(iter_trait_id); + if let Some(repeat_kind) = parse_repeat_arg(cx, repeat_arg); + let ctxt = collect_expr.span.ctxt(); + if ctxt == take_expr.span.ctxt(); + if ctxt == take_self_arg.span.ctxt(); + then { + let mut app = Applicability::MachineApplicable; + let count_snip = snippet_with_context(cx, take_arg.span, ctxt, "..", &mut app).0; + + let val_str = match repeat_kind { + RepeatKind::Char(_) if repeat_arg.span.ctxt() != ctxt => return, + RepeatKind::Char('\'') => r#""'""#.into(), + RepeatKind::Char('"') => r#""\"""#.into(), + RepeatKind::Char(_) => + match snippet_with_applicability(cx, repeat_arg.span, "..", &mut app) { + Cow::Owned(s) => Cow::Owned(format!("\"{}\"", &s[1..s.len() - 1])), + s @ Cow::Borrowed(_) => s, + }, + RepeatKind::String => + Sugg::hir_with_context(cx, repeat_arg, ctxt, "..", &mut app).maybe_par().to_string().into(), + }; + + span_lint_and_sugg( + cx, + MANUAL_STR_REPEAT, + collect_expr.span, + "manual implementation of `str::repeat` using iterators", + "try this", + format!("{}.repeat({})", val_str, count_snip), + app + ) + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 0b1b6304def..c8ae972f18c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -32,6 +32,7 @@ mod iter_nth_zero; mod iter_skip_next; mod iterator_step_by_zero; mod manual_saturating_arithmetic; +mod manual_str_repeat; mod map_collect_result_unit; mod map_flatten; mod map_unwrap_or; @@ -48,6 +49,7 @@ mod single_char_push_string; mod skip_while_next; mod string_extend_chars; mod suspicious_map; +mod suspicious_splitn; mod uninit_assumed_init; mod unnecessary_filter_map; mod unnecessary_fold; @@ -61,7 +63,7 @@ mod zst_offset; use bind_instead_of_map::BindInsteadOfMap; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::ty::{contains_adt_constructor, contains_ty, implements_trait, is_copy, is_type_diagnostic_item}; -use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, paths, return_ty}; +use clippy_utils::{contains_return, get_trait_def_id, in_macro, iter_input_pats, meets_msrv, msrvs, paths, return_ty}; use if_chain::if_chain; use rustc_hir as hir; use rustc_hir::def::Res; @@ -283,30 +285,6 @@ declare_clippy_lint! { } declare_clippy_lint! { - /// **What it does:** This is the same as - /// [`wrong_self_convention`](#wrong_self_convention), but for public items. - /// - /// **Why is this bad?** See [`wrong_self_convention`](#wrong_self_convention). - /// - /// **Known problems:** Actually *renaming* the function may break clients if - /// the function is part of the public interface. In that case, be mindful of - /// the stability guarantees you've given your users. - /// - /// **Example:** - /// ```rust - /// # struct X; - /// impl<'a> X { - /// pub fn as_str(self) -> &'a str { - /// "foo" - /// } - /// } - /// ``` - pub WRONG_PUB_SELF_CONVENTION, - restriction, - "defining a public method named with an established prefix (like \"into_\") that takes `self` with the wrong convention" -} - -declare_clippy_lint! { /// **What it does:** Checks for usage of `ok().expect(..)`. /// /// **Why is this bad?** Because you usually call `expect()` on the `Result` @@ -1657,14 +1635,69 @@ declare_clippy_lint! { "replace `.iter().count()` with `.len()`" } +declare_clippy_lint! { + /// **What it does:** Checks for calls to [`splitn`] + /// (https://doc.rust-lang.org/std/primitive.str.html#method.splitn) and + /// related functions with either zero or one splits. + /// + /// **Why is this bad?** These calls don't actually split the value and are + /// likely to be intended as a different number. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// let s = ""; + /// for x in s.splitn(1, ":") { + /// // use x + /// } + /// + /// // Good + /// let s = ""; + /// for x in s.splitn(2, ":") { + /// // use x + /// } + /// ``` + pub SUSPICIOUS_SPLITN, + correctness, + "checks for `.splitn(0, ..)` and `.splitn(1, ..)`" +} + +declare_clippy_lint! { + /// **What it does:** Checks for manual implementations of `str::repeat` + /// + /// **Why is this bad?** These are both harder to read, as well as less performant. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// let x: String = std::iter::repeat('x').take(10).collect(); + /// + /// // Good + /// let x: String = "x".repeat(10); + /// ``` + pub MANUAL_STR_REPEAT, + perf, + "manual implementation of `str::repeat`" +} + pub struct Methods { + avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>, } impl Methods { #[must_use] - pub fn new(msrv: Option<RustcVersion>) -> Self { - Self { msrv } + pub fn new(avoid_breaking_exported_api: bool, msrv: Option<RustcVersion>) -> Self { + Self { + avoid_breaking_exported_api, + msrv, + } } } @@ -1673,7 +1706,6 @@ impl_lint_pass!(Methods => [ EXPECT_USED, SHOULD_IMPLEMENT_TRAIT, WRONG_SELF_CONVENTION, - WRONG_PUB_SELF_CONVENTION, OK_EXPECT, MAP_UNWRAP_OR, RESULT_MAP_OR_INTO_OPTION, @@ -1726,7 +1758,9 @@ impl_lint_pass!(Methods => [ MAP_COLLECT_RESULT_UNIT, FROM_ITER_INSTEAD_OF_COLLECT, INSPECT_FOR_EACH, - IMPLICIT_CLONE + IMPLICIT_CLONE, + SUSPICIOUS_SPLITN, + MANUAL_STR_REPEAT ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -1838,16 +1872,20 @@ impl<'tcx> LateLintPass<'tcx> for Methods { } } - wrong_self_convention::check( - cx, - &name, - item.vis.node.is_pub(), - self_ty, - first_arg_ty, - first_arg.pat.span, - implements_trait, - false - ); + if sig.decl.implicit_self.has_implicit_self() + && !(self.avoid_breaking_exported_api + && cx.access_levels.is_exported(impl_item.hir_id())) + { + wrong_self_convention::check( + cx, + &name, + self_ty, + first_arg_ty, + first_arg.pat.span, + implements_trait, + false + ); + } } } @@ -1903,7 +1941,9 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if_chain! { if let TraitItemKind::Fn(ref sig, _) = item.kind; + if sig.decl.implicit_self.has_implicit_self(); if let Some(first_arg_ty) = sig.decl.inputs.iter().next(); + then { let first_arg_span = first_arg_ty.span; let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); @@ -1911,7 +1951,6 @@ impl<'tcx> LateLintPass<'tcx> for Methods { wrong_self_convention::check( cx, &item.ident.name.as_str(), - false, self_ty, first_arg_ty, first_arg_span, @@ -1947,7 +1986,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio if let Some((name, [recv, args @ ..], span)) = method_call!(expr) { match (name, args) { ("add" | "offset" | "sub" | "wrapping_offset" | "wrapping_add" | "wrapping_sub", [recv, _]) => { - zst_offset::check(cx, expr, recv) + zst_offset::check(cx, expr, recv); }, ("and_then", [arg]) => { let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg); @@ -1965,6 +2004,11 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio Some(("map", [m_recv, m_arg], _)) => { map_collect_result_unit::check(cx, expr, m_recv, m_arg, recv); }, + Some(("take", [take_self_arg, take_arg], _)) => { + if meets_msrv(msrv, &msrvs::STR_REPEAT) { + manual_str_repeat::check(cx, expr, recv, take_self_arg, take_arg); + } + }, _ => {}, }, ("count", []) => match method_call!(recv) { @@ -2008,7 +2052,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio ("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, msrv), ("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, msrv), ("filter", [f_arg]) => { - filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false) + filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, false); }, ("find", [f_arg]) => filter_map::check(cx, expr, recv2, f_arg, span2, recv, m_arg, span, true), _ => {}, @@ -2040,6 +2084,9 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio unnecessary_lazy_eval::check(cx, expr, recv, arg, "or"); } }, + ("splitn" | "splitn_mut" | "rsplitn" | "rsplitn_mut", [count_arg, _]) => { + suspicious_splitn::check(cx, name, expr, recv, count_arg); + }, ("step_by", [arg]) => iterator_step_by_zero::check(cx, expr, arg), ("to_os_string" | "to_owned" | "to_path_buf" | "to_vec", []) => { implicit_clone::check(cx, name, expr, recv, span); @@ -2054,7 +2101,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio manual_saturating_arithmetic::check(cx, expr, lhs, rhs, u_arg, &arith["checked_".len()..]); }, Some(("map", [m_recv, m_arg], span)) => { - option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span) + option_map_unwrap_or::check(cx, expr, m_recv, m_arg, recv, u_arg, span); }, _ => {}, }, @@ -2069,7 +2116,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio fn check_is_some_is_none(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, is_some: bool) { if let Some((name @ ("find" | "position" | "rposition"), [f_recv, arg], span)) = method_call!(recv) { - search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span) + search_is_some::check(cx, expr, name, is_some, f_recv, arg, recv, span); } } diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs new file mode 100644 index 00000000000..a271df60572 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs @@ -0,0 +1,56 @@ +use clippy_utils::consts::{constant, Constant}; +use clippy_utils::diagnostics::span_lint_and_note; +use if_chain::if_chain; +use rustc_ast::LitKind; +use rustc_hir::{Expr, ExprKind}; +use rustc_lint::LateContext; +use rustc_span::source_map::Spanned; + +use super::SUSPICIOUS_SPLITN; + +pub(super) fn check( + cx: &LateContext<'_>, + method_name: &str, + expr: &Expr<'_>, + self_arg: &Expr<'_>, + count_arg: &Expr<'_>, +) { + if_chain! { + if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg); + if count <= 1; + if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); + if let Some(impl_id) = cx.tcx.impl_of_method(call_id); + let lang_items = cx.tcx.lang_items(); + if lang_items.slice_impl() == Some(impl_id) || lang_items.str_impl() == Some(impl_id); + then { + // Ignore empty slice and string literals when used with a literal count. + if (matches!(self_arg.kind, ExprKind::Array([])) + || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty()) + ) && matches!(count_arg.kind, ExprKind::Lit(_)) + { + return; + } + + let (msg, note_msg) = if count == 0 { + (format!("`{}` called with `0` splits", method_name), + "the resulting iterator will always return `None`") + } else { + (format!("`{}` called with `1` split", method_name), + if lang_items.slice_impl() == Some(impl_id) { + "the resulting iterator will always return the entire slice followed by `None`" + } else { + "the resulting iterator will always return the entire string followed by `None`" + }) + }; + + span_lint_and_note( + cx, + SUSPICIOUS_SPLITN, + expr.span, + &msg, + None, + note_msg, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs index 75517c48a21..4c4034437da 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -87,7 +87,7 @@ pub(super) fn check( ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true), ast::LitKind::Int(0, _) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Add, "sum", false), ast::LitKind::Int(1, _) => { - check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false) + check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Mul, "product", false); }, _ => (), } diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs index 6e2bcb113c2..a2e09e5ecec 100644 --- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs +++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs @@ -6,7 +6,6 @@ use rustc_middle::ty::TyS; use rustc_span::source_map::Span; use std::fmt; -use super::WRONG_PUB_SELF_CONVENTION; use super::WRONG_SELF_CONVENTION; #[rustfmt::skip] @@ -21,9 +20,9 @@ const CONVENTIONS: [(&[Convention], &[SelfKind]); 9] = [ // Conversion using `to_` can use borrowed (non-Copy types) or owned (Copy types). // Source: https://rust-lang.github.io/api-guidelines/naming.html#ad-hoc-conversions-follow-as_-to_-into_-conventions-c-conv - (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), - Convention::IsTraitItem(false)], &[SelfKind::Ref]), - (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), + (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(false), + Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Ref]), + (&[Convention::StartsWith("to_"), Convention::NotEndsWith("_mut"), Convention::IsSelfTypeCopy(true), Convention::IsTraitItem(false), Convention::ImplementsTrait(false)], &[SelfKind::Value]), ]; @@ -85,18 +84,12 @@ impl fmt::Display for Convention { pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, item_name: &str, - is_pub: bool, self_ty: &'tcx TyS<'tcx>, first_arg_ty: &'tcx TyS<'tcx>, first_arg_span: Span, implements_trait: bool, is_trait_item: bool, ) { - let lint = if is_pub { - WRONG_PUB_SELF_CONVENTION - } else { - WRONG_SELF_CONVENTION - }; if let Some((conventions, self_kinds)) = &CONVENTIONS.iter().find(|(convs, _)| { convs .iter() @@ -142,7 +135,7 @@ pub(super) fn check<'tcx>( span_lint_and_help( cx, - lint, + WRONG_SELF_CONVENTION, first_arg_span, &format!( "{} usually take {}", diff --git a/src/tools/clippy/clippy_lints/src/minmax.rs b/src/tools/clippy/clippy_lints/src/minmax.rs index 45948f4d926..ff3473b744e 100644 --- a/src/tools/clippy/clippy_lints/src/minmax.rs +++ b/src/tools/clippy/clippy_lints/src/minmax.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant_simple, Constant}; +use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{match_def_path, match_trait_method, paths}; use if_chain::if_chain; diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 6966d798c53..804c04fe1b8 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -17,7 +17,7 @@ use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{ExpnKind, Span}; use rustc_span::symbol::sym; -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::sugg::Sugg; use clippy_utils::{ expr_path_res, get_item_name, get_parent_expr, higher, in_constant, is_diag_trait_item, is_integer_const, @@ -355,8 +355,10 @@ impl<'tcx> LateLintPass<'tcx> for MiscLints { if binop.node == BinOpKind::And || binop.node == BinOpKind::Or; if let Some(sugg) = Sugg::hir_opt(cx, a); then { - span_lint_and_then(cx, + span_lint_hir_and_then( + cx, SHORT_CIRCUIT_STATEMENT, + expr.hir_id, stmt.span, "boolean short circuit operator in statement may be clearer using an explicit test", |diag| { @@ -660,7 +662,14 @@ fn in_attributes_expansion(expr: &Expr<'_>) -> bool { use rustc_span::hygiene::MacroKind; if expr.span.from_expansion() { let data = expr.span.ctxt().outer_expn_data(); - matches!(data.kind, ExpnKind::Macro { kind: MacroKind::Attr, name: _, proc_macro: _ }) + matches!( + data.kind, + ExpnKind::Macro { + kind: MacroKind::Attr, + name: _, + proc_macro: _ + } + ) } else { false } diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs index dd38316fa25..050b6805b7c 100644 --- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs +++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs @@ -310,7 +310,7 @@ impl EarlyLintPass for MiscEarlyLints { if in_external_macro(cx.sess(), expr.span) { return; } - double_neg::check(cx, expr) + double_neg::check(cx, expr); } } @@ -334,15 +334,15 @@ impl MiscEarlyLints { }; unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "integer"); if lit_snip.starts_with("0x") { - mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip) + mixed_case_hex_literals::check(cx, lit, suffix, &lit_snip); } else if lit_snip.starts_with("0b") || lit_snip.starts_with("0o") { - /* nothing to do */ + // nothing to do } else if value != 0 && lit_snip.starts_with('0') { - zero_prefixed_literal::check(cx, lit, &lit_snip) + zero_prefixed_literal::check(cx, lit, &lit_snip); } } else if let LitKind::Float(_, LitFloatType::Suffixed(float_ty)) = lit.kind { let suffix = float_ty.name_str(); - unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float") + unseparated_literal_suffix::check(cx, lit, &lit_snip, suffix, "float"); } } } diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs index dfab3e8a931..ec1572c26c2 100644 --- a/src/tools/clippy/clippy_lints/src/missing_doc.rs +++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs @@ -93,9 +93,9 @@ impl MissingDoc { return; } - let has_doc = attrs.iter().any(|a| { - a.is_doc_comment() || a.doc_str().is_some() || a.value_str().is_some() || Self::has_include(a.meta()) - }); + let has_doc = attrs + .iter() + .any(|a| a.doc_str().is_some() || Self::has_include(a.meta())); if !has_doc { span_lint( cx, diff --git a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs index 64e9dc85466..1414fdc1b11 100644 --- a/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/modulo_arithmetic.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::sext; use if_chain::if_chain; diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index cea6fce1195..6efe8ffcde0 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { let def_id = cx.typeck_results().type_dependent_def_id(e.hir_id).unwrap(); let substs = cx.typeck_results().node_substs(e.hir_id); let method_type = cx.tcx.type_of(def_id).subst(cx.tcx, substs); - check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method") + check_arguments(cx, arguments, method_type, &path.ident.as_str(), "method"); }, _ => (), } diff --git a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs index 7dfe12cd4eb..25645a0e7a2 100644 --- a/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs +++ b/src/tools/clippy/clippy_lints/src/mutable_debug_assertion.rs @@ -107,7 +107,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MutArgVisitor<'a, 'tcx> { _ if !self.found => self.expr_span = Some(expr.span), _ => return, } - walk_expr(self, expr) + walk_expr(self, expr); } fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs index 3e2b2782ed5..fe3c4455be5 100644 --- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs @@ -121,7 +121,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { match &p.ty.kind { TyKind::Path(None, path) => { if let PatKind::Ident(BindingMode::ByValue(mutbl), _, _) = p.pat.kind { - check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl) + check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Value, mutbl); } }, TyKind::Rptr(lifetime, mut_ty) => { @@ -129,7 +129,7 @@ impl EarlyLintPass for NeedlessArbitrarySelfType { if let TyKind::Path(None, path) = &mut_ty.ty.kind; if let PatKind::Ident(BindingMode::ByValue(Mutability::Not), _, _) = p.pat.kind; then { - check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl) + check_param_inner(cx, path, p.span.to(p.ty.span), &Mode::Ref(*lifetime), mut_ty.mutbl); } } }, diff --git a/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs new file mode 100644 index 00000000000..b30bfbd4294 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/needless_bitwise_bool.rs @@ -0,0 +1,86 @@ +use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::in_macro; +use clippy_utils::source::snippet_opt; +use if_chain::if_chain; +use rustc_errors::Applicability; +use rustc_hir::{BinOpKind, Expr, ExprKind}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// **What it does:** + /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using + /// a lazy and. + /// + /// **Why is this bad?** + /// The bitwise operators do not support short-circuiting, so it may hinder code performance. + /// Additionally, boolean logic "masked" as bitwise logic is not caught by lints like `unnecessary_fold` + /// + /// **Known problems:** + /// This lint evaluates only when the right side is determined to have no side effects. At this time, that + /// determination is quite conservative. + /// + /// **Example:** + /// + /// ```rust + /// let (x,y) = (true, false); + /// if x & !y {} // where both x and y are booleans + /// ``` + /// Use instead: + /// ```rust + /// let (x,y) = (true, false); + /// if x && !y {} + /// ``` + pub NEEDLESS_BITWISE_BOOL, + pedantic, + "Boolean expressions that use bitwise rather than lazy operators" +} + +declare_lint_pass!(NeedlessBitwiseBool => [NEEDLESS_BITWISE_BOOL]); + +fn is_bitwise_operation(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { + let ty = cx.typeck_results().expr_ty(expr); + if_chain! { + if !in_macro(expr.span); + if let (&ExprKind::Binary(ref op, _, right), &ty::Bool) = (&expr.kind, &ty.kind()); + if op.node == BinOpKind::BitAnd || op.node == BinOpKind::BitOr; + if let ExprKind::Call(..) | ExprKind::MethodCall(..) | ExprKind::Binary(..) | ExprKind::Unary(..) = right.kind; + if !right.can_have_side_effects(); + then { + return true; + } + } + false +} + +fn suggession_snippet(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> { + if let ExprKind::Binary(ref op, left, right) = expr.kind { + if let (Some(l_snippet), Some(r_snippet)) = (snippet_opt(cx, left.span), snippet_opt(cx, right.span)) { + let op_snippet = match op.node { + BinOpKind::BitAnd => "&&", + _ => "||", + }; + return Some(format!("{} {} {}", l_snippet, op_snippet, r_snippet)); + } + } + None +} + +impl LateLintPass<'_> for NeedlessBitwiseBool { + fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { + if is_bitwise_operation(cx, expr) { + span_lint_and_then( + cx, + NEEDLESS_BITWISE_BOOL, + expr.span, + "use of bitwise operator instead of lazy operator between booleans", + |diag| { + if let Some(sugg) = suggession_snippet(cx, expr) { + diag.span_suggestion(expr.span, "try", sugg, Applicability::MachineApplicable); + } + }, + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index dd458198637..3b3736fd3a1 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -82,7 +82,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { } if is_else_clause(cx.tcx, e) { - snip = snip.blockify() + snip = snip.blockify(); } span_lint_and_sugg( @@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { |h: Sugg<'_>| !h, "equality checks against false can be replaced by a negation", )); - check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal) + check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); }, BinOpKind::Ne => { let true_case = Some(( @@ -152,7 +152,7 @@ impl<'tcx> LateLintPass<'tcx> for BoolComparison { "inequality checks against true can be replaced by a negation", )); let false_case = Some((|h| h, "inequality checks against false are unnecessary")); - check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal) + check_comparison(cx, e, true_case, false_case, true_case, false_case, ignore_no_literal); }, BinOpKind::Lt => check_comparison( cx, @@ -251,22 +251,22 @@ fn check_comparison<'a, 'tcx>( snippet_with_applicability(cx, expression_info.right_span, "..", &mut applicability) ), applicability, - ) + ); } } match (fetch_bool_expr(left_side), fetch_bool_expr(right_side)) { (Bool(true), Other) => left_true.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, right_side, applicability, m, h) + suggest_bool_comparison(cx, e, right_side, applicability, m, h); }), (Other, Bool(true)) => right_true.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, left_side, applicability, m, h) + suggest_bool_comparison(cx, e, left_side, applicability, m, h); }), (Bool(false), Other) => left_false.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, right_side, applicability, m, h) + suggest_bool_comparison(cx, e, right_side, applicability, m, h); }), (Other, Bool(false)) => right_false.map_or((), |(h, m)| { - suggest_bool_comparison(cx, e, left_side, applicability, m, h) + suggest_bool_comparison(cx, e, left_side, applicability, m, h); }), (Other, Other) => no_literal.map_or((), |(h, m)| { let left_side = Sugg::hir_with_applicability(cx, left_side, "..", &mut applicability); @@ -279,7 +279,7 @@ fn check_comparison<'a, 'tcx>( "try simplifying it as shown", h(left_side, right_side).to_string(), applicability, - ) + ); }), _ => (), } diff --git a/src/tools/clippy/clippy_lints/src/needless_borrow.rs b/src/tools/clippy/clippy_lints/src/needless_borrow.rs index eef3c16730b..dd1dfa2bdfb 100644 --- a/src/tools/clippy/clippy_lints/src/needless_borrow.rs +++ b/src/tools/clippy/clippy_lints/src/needless_borrow.rs @@ -3,16 +3,18 @@ //! This lint is **warn** by default use clippy_utils::diagnostics::span_lint_and_then; -use clippy_utils::is_automatically_derived; -use clippy_utils::source::snippet_opt; +use clippy_utils::source::{snippet_opt, snippet_with_applicability, snippet_with_context}; +use clippy_utils::{get_parent_expr, in_macro, path_to_local}; use if_chain::if_chain; +use rustc_ast::util::parser::PREC_POSTFIX; +use rustc_data_structures::fx::FxIndexMap; use rustc_errors::Applicability; -use rustc_hir::{BindingAnnotation, BorrowKind, Expr, ExprKind, Item, Mutability, Pat, PatKind}; +use rustc_hir::{BindingAnnotation, Body, BodyId, BorrowKind, Expr, ExprKind, HirId, Mutability, Pat, PatKind, UnOp}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::def_id::LocalDefId; +use rustc_span::Span; declare_clippy_lint! { /// **What it does:** Checks for address of operations (`&`) that are going to @@ -32,20 +34,70 @@ declare_clippy_lint! { /// let x: &i32 = &5; /// ``` pub NEEDLESS_BORROW, - nursery, + style, "taking a reference that is going to be automatically dereferenced" } +declare_clippy_lint! { + /// **What it does:** Checks for `ref` bindings which create a reference to a reference. + /// + /// **Why is this bad?** The address-of operator at the use site is clearer about the need for a reference. + /// + /// **Known problems:** None. + /// + /// **Example:** + /// ```rust + /// // Bad + /// let x = Some(""); + /// if let Some(ref x) = x { + /// // use `x` here + /// } + /// + /// // Good + /// let x = Some(""); + /// if let Some(x) = x { + /// // use `&x` here + /// } + /// ``` + pub REF_BINDING_TO_REFERENCE, + pedantic, + "`ref` binding to a reference" +} + +impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW, REF_BINDING_TO_REFERENCE]); #[derive(Default)] pub struct NeedlessBorrow { - derived_item: Option<LocalDefId>, + /// The body the first local was found in. Used to emit lints when the traversal of the body has + /// been finished. Note we can't lint at the end of every body as they can be nested within each + /// other. + current_body: Option<BodyId>, + /// The list of locals currently being checked by the lint. + /// If the value is `None`, then the binding has been seen as a ref pattern, but is not linted. + /// This is needed for or patterns where one of the branches can be linted, but another can not + /// be. + /// + /// e.g. `m!(x) | Foo::Bar(ref x)` + ref_locals: FxIndexMap<HirId, Option<RefPat>>, } -impl_lint_pass!(NeedlessBorrow => [NEEDLESS_BORROW]); +struct RefPat { + /// Whether every usage of the binding is dereferenced. + always_deref: bool, + /// The spans of all the ref bindings for this local. + spans: Vec<Span>, + /// The applicability of this suggestion. + app: Applicability, + /// All the replacements which need to be made. + replacements: Vec<(Span, String)>, +} impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { - if e.span.from_expansion() || self.derived_item.is_some() { + if let Some(local) = path_to_local(e) { + self.check_local_usage(cx, e, local); + } + + if e.span.from_expansion() { return; } if let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = e.kind { @@ -85,50 +137,131 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrow { } } } + fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { - if pat.span.from_expansion() || self.derived_item.is_some() { - return; + if let PatKind::Binding(BindingAnnotation::Ref, id, name, _) = pat.kind { + if let Some(opt_prev_pat) = self.ref_locals.get_mut(&id) { + // This binding id has been seen before. Add this pattern to the list of changes. + if let Some(prev_pat) = opt_prev_pat { + if in_macro(pat.span) { + // Doesn't match the context of the previous pattern. Can't lint here. + *opt_prev_pat = None; + } else { + prev_pat.spans.push(pat.span); + prev_pat.replacements.push(( + pat.span, + snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut prev_pat.app) + .0 + .into(), + )); + } + } + return; + } + + if_chain! { + if !in_macro(pat.span); + if let ty::Ref(_, tam, _) = *cx.typeck_results().pat_ty(pat).kind(); + // only lint immutable refs, because borrowed `&mut T` cannot be moved out + if let ty::Ref(_, _, Mutability::Not) = *tam.kind(); + then { + let mut app = Applicability::MachineApplicable; + let snip = snippet_with_context(cx, name.span, pat.span.ctxt(), "..", &mut app).0; + self.current_body = self.current_body.or(cx.enclosing_body); + self.ref_locals.insert( + id, + Some(RefPat { + always_deref: true, + spans: vec![pat.span], + app, + replacements: vec![(pat.span, snip.into())], + }), + ); + } + } } - if_chain! { - if let PatKind::Binding(BindingAnnotation::Ref, .., name, _) = pat.kind; - if let ty::Ref(_, tam, mutbl) = *cx.typeck_results().pat_ty(pat).kind(); - if mutbl == Mutability::Not; - if let ty::Ref(_, _, mutbl) = *tam.kind(); - // only lint immutable refs, because borrowed `&mut T` cannot be moved out - if mutbl == Mutability::Not; - then { + } + + fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) { + if Some(body.id()) == self.current_body { + for pat in self.ref_locals.drain(..).filter_map(|(_, x)| x) { + let replacements = pat.replacements; + let app = pat.app; span_lint_and_then( cx, - NEEDLESS_BORROW, - pat.span, + if pat.always_deref { + NEEDLESS_BORROW + } else { + REF_BINDING_TO_REFERENCE + }, + pat.spans, "this pattern creates a reference to a reference", |diag| { - if let Some(snippet) = snippet_opt(cx, name.span) { - diag.span_suggestion( - pat.span, - "change this to", - snippet, - Applicability::MachineApplicable, - ); - } - } - ) + diag.multipart_suggestion("try this", replacements, app); + }, + ); } + self.current_body = None; } } - - fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'_>) { - let attrs = cx.tcx.hir().attrs(item.hir_id()); - if is_automatically_derived(attrs) { - debug_assert!(self.derived_item.is_none()); - self.derived_item = Some(item.def_id); - } - } - - fn check_item_post(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'_>) { - if let Some(id) = self.derived_item { - if item.def_id == id { - self.derived_item = None; +} +impl NeedlessBorrow { + fn check_local_usage(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, local: HirId) { + if let Some(outer_pat) = self.ref_locals.get_mut(&local) { + if let Some(pat) = outer_pat { + // Check for auto-deref + if !matches!( + cx.typeck_results().expr_adjustments(e), + [ + Adjustment { + kind: Adjust::Deref(_), + .. + }, + Adjustment { + kind: Adjust::Deref(_), + .. + }, + .. + ] + ) { + match get_parent_expr(cx, e) { + // Field accesses are the same no matter the number of references. + Some(Expr { + kind: ExprKind::Field(..), + .. + }) => (), + Some(&Expr { + span, + kind: ExprKind::Unary(UnOp::Deref, _), + .. + }) if !in_macro(span) => { + // Remove explicit deref. + let snip = snippet_with_context(cx, e.span, span.ctxt(), "..", &mut pat.app).0; + pat.replacements.push((span, snip.into())); + }, + Some(parent) if !in_macro(parent.span) => { + // Double reference might be needed at this point. + if parent.precedence().order() == PREC_POSTFIX { + // Parentheses would be needed here, don't lint. + *outer_pat = None; + } else { + pat.always_deref = false; + let snip = snippet_with_context(cx, e.span, parent.span.ctxt(), "..", &mut pat.app).0; + pat.replacements.push((e.span, format!("&{}", snip))); + } + }, + _ if !in_macro(e.span) => { + // Double reference might be needed at this point. + pat.always_deref = false; + let snip = snippet_with_applicability(cx, e.span, "..", &mut pat.app); + pat.replacements.push((e.span, format!("&{}", snip))); + }, + // Edge case for macros. The span of the identifier will usually match the context of the + // binding, but not if the identifier was created in a macro. e.g. `concat_idents` and proc + // macros + _ => *outer_pat = None, + } + } } } } diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs index 079b6642d58..a723a472a25 100644 --- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs +++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs @@ -142,10 +142,10 @@ impl<'tcx> Visitor<'tcx> for RetCollector { match expr.kind { ExprKind::Ret(..) => { if self.loop_depth > 0 && !self.ret_in_loop { - self.ret_in_loop = true + self.ret_in_loop = true; } - self.spans.push(expr.span) + self.spans.push(expr.span); }, ExprKind::Loop(..) => { diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs index 7b156a8c49d..c64491c63e2 100644 --- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs @@ -1,14 +1,13 @@ use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_lang_ctor; use clippy_utils::source::snippet; -use clippy_utils::ty::is_type_diagnostic_item; -use clippy_utils::{differing_macro_contexts, is_lang_ctor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::{OptionSome, ResultOk}; use rustc_hir::{Body, Expr, ExprKind, LangItem, MatchSource, QPath}; use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty::TyS; use rustc_session::{declare_lint_pass, declare_tool_lint}; -use rustc_span::sym; declare_clippy_lint! { /// **What it does:** @@ -63,12 +62,6 @@ declare_clippy_lint! { declare_lint_pass!(NeedlessQuestionMark => [NEEDLESS_QUESTION_MARK]); -#[derive(Debug)] -enum SomeOkCall<'a> { - SomeCall(&'a Expr<'a>, &'a Expr<'a>), - OkCall(&'a Expr<'a>, &'a Expr<'a>), -} - impl LateLintPass<'_> for NeedlessQuestionMark { /* * The question mark operator is compatible with both Result<T, E> and Option<T>, @@ -90,104 +83,37 @@ impl LateLintPass<'_> for NeedlessQuestionMark { */ fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - let e = match &expr.kind { - ExprKind::Ret(Some(e)) => e, - _ => return, - }; - - if let Some(ok_some_call) = is_some_or_ok_call(cx, e) { - emit_lint(cx, &ok_some_call); + if let ExprKind::Ret(Some(e)) = expr.kind { + check(cx, e); } } fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) { - // Function / Closure block - let expr_opt = if let ExprKind::Block(block, _) = &body.value.kind { - block.expr - } else { - // Single line closure - Some(&body.value) - }; - - if_chain! { - if let Some(expr) = expr_opt; - if let Some(ok_some_call) = is_some_or_ok_call(cx, expr); - then { - emit_lint(cx, &ok_some_call); - } - }; + check(cx, body.value.peel_blocks()); } } -fn emit_lint(cx: &LateContext<'_>, expr: &SomeOkCall<'_>) { - let (entire_expr, inner_expr) = match expr { - SomeOkCall::OkCall(outer, inner) | SomeOkCall::SomeCall(outer, inner) => (outer, inner), +fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { + let inner_expr = if_chain! { + if let ExprKind::Call(path, [arg]) = &expr.kind; + if let ExprKind::Path(ref qpath) = &path.kind; + if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk); + if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &arg.kind; + if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind; + if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, _)) = &called.kind; + if expr.span.ctxt() == inner_expr.span.ctxt(); + let expr_ty = cx.typeck_results().expr_ty(expr); + let inner_ty = cx.typeck_results().expr_ty(inner_expr); + if TyS::same_type(expr_ty, inner_ty); + then { inner_expr } else { return; } }; - span_lint_and_sugg( cx, NEEDLESS_QUESTION_MARK, - entire_expr.span, + expr.span, "question mark operator is useless here", "try", format!("{}", snippet(cx, inner_expr.span, r#""...""#)), Applicability::MachineApplicable, ); } - -fn is_some_or_ok_call<'a>(cx: &'a LateContext<'_>, expr: &'a Expr<'_>) -> Option<SomeOkCall<'a>> { - if_chain! { - // Check outer expression matches CALL_IDENT(ARGUMENT) format - if let ExprKind::Call(path, args) = &expr.kind; - if let ExprKind::Path(ref qpath) = &path.kind; - if is_lang_ctor(cx, qpath, OptionSome) || is_lang_ctor(cx, qpath, ResultOk); - - // Extract inner expression from ARGUMENT - if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar) = &args[0].kind; - if let ExprKind::Call(called, args) = &inner_expr_with_q.kind; - if args.len() == 1; - - if let ExprKind::Path(QPath::LangItem(LangItem::TryIntoResult, _)) = &called.kind; - then { - // Extract inner expr type from match argument generated by - // question mark operator - let inner_expr = &args[0]; - - // if the inner expr is inside macro but the outer one is not, do not lint (#6921) - if differing_macro_contexts(expr.span, inner_expr.span) { - return None; - } - - let inner_ty = cx.typeck_results().expr_ty(inner_expr); - let outer_ty = cx.typeck_results().expr_ty(expr); - - // Check if outer and inner type are Option - let outer_is_some = is_type_diagnostic_item(cx, outer_ty, sym::option_type); - let inner_is_some = is_type_diagnostic_item(cx, inner_ty, sym::option_type); - - // Check for Option MSRV - if outer_is_some && inner_is_some { - return Some(SomeOkCall::SomeCall(expr, inner_expr)); - } - - // Check if outer and inner type are Result - let outer_is_result = is_type_diagnostic_item(cx, outer_ty, sym::result_type); - let inner_is_result = is_type_diagnostic_item(cx, inner_ty, sym::result_type); - - // Additional check: if the error type of the Result can be converted - // via the From trait, then don't match - let does_not_call_from = !has_implicit_error_from(cx, expr, inner_expr); - - // Must meet Result MSRV - if outer_is_result && inner_is_result && does_not_call_from { - return Some(SomeOkCall::OkCall(expr, inner_expr)); - } - } - } - - None -} - -fn has_implicit_error_from(cx: &LateContext<'_>, entire_expr: &Expr<'_>, inner_result_expr: &Expr<'_>) -> bool { - return cx.typeck_results().expr_ty(entire_expr) != cx.typeck_results().expr_ty(inner_result_expr); -} diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs index 0704173a011..c824f6f54b5 100644 --- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs +++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs @@ -84,7 +84,7 @@ impl<'tcx> LateLintPass<'tcx> for NoNegCompOpForPartialOrd { types produces code that is hard to read and refactor, please \ consider using the `partial_cmp` method instead, to make it \ clear that the two values could be incomparable" - ) + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs index 34fd012572f..d5e1ea6d242 100644 --- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs +++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs @@ -1,3 +1,4 @@ +use clippy_utils::consts::{self, Constant}; use clippy_utils::diagnostics::span_lint; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp}; @@ -5,8 +6,6 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; -use crate::consts::{self, Constant}; - declare_clippy_lint! { /// **What it does:** Checks for multiplication by -1 as a form of negation. /// diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs index cfcaf509471..b2206a82208 100644 --- a/src/tools/clippy/clippy_lints/src/no_effect.rs +++ b/src/tools/clippy/clippy_lints/src/no_effect.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; +use clippy_utils::diagnostics::{span_lint_hir, span_lint_hir_and_then}; use clippy_utils::source::snippet_opt; use clippy_utils::ty::has_drop; use rustc_errors::Applicability; @@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect { fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) { if let StmtKind::Semi(expr) = stmt.kind { if has_no_effect(cx, expr) { - span_lint(cx, NO_EFFECT, stmt.span, "statement with no effect"); + span_lint_hir(cx, NO_EFFECT, expr.hir_id, stmt.span, "statement with no effect"); } else if let Some(reduced) = reduce_expression(cx, expr) { let mut snippet = String::new(); for e in reduced { @@ -106,14 +106,15 @@ impl<'tcx> LateLintPass<'tcx> for NoEffect { return; } } - span_lint_and_sugg( + span_lint_hir_and_then( cx, UNNECESSARY_OPERATION, + expr.hir_id, stmt.span, "statement can be reduced", - "replace it with", - snippet, - Applicability::MachineApplicable, + |diag| { + diag.span_suggestion(stmt.span, "replace it with", snippet, Applicability::MachineApplicable); + }, ); } } diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs index 4c8bceaf2cb..5292af5f076 100644 --- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs +++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs @@ -126,6 +126,7 @@ const ALLOWED_TO_BE_SIMILAR: &[&[&str]] = &[ &["args", "arms"], &["qpath", "path"], &["lit", "lint"], + &["wparam", "lparam"], ]; struct SimilarNamesNameVisitor<'a, 'tcx, 'b>(&'b mut SimilarNamesLocalVisitor<'a, 'tcx>); diff --git a/src/tools/clippy/clippy_lints/src/open_options.rs b/src/tools/clippy/clippy_lints/src/open_options.rs index 9efe45336bf..fded48038e3 100644 --- a/src/tools/clippy/clippy_lints/src/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/open_options.rs @@ -123,7 +123,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `create` is called more than once", ); } else { - create = true + create = true; } create_arg = create_arg || (arg == Argument::True); }, @@ -136,7 +136,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `append` is called more than once", ); } else { - append = true + append = true; } append_arg = append_arg || (arg == Argument::True); }, @@ -149,7 +149,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `truncate` is called more than once", ); } else { - truncate = true + truncate = true; } truncate_arg = truncate_arg || (arg == Argument::True); }, @@ -162,7 +162,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `read` is called more than once", ); } else { - read = true + read = true; } read_arg = read_arg || (arg == Argument::True); }, @@ -175,7 +175,7 @@ fn check_open_options(cx: &LateContext<'_>, options: &[(OpenOption, Argument)], "the method `write` is called more than once", ); } else { - write = true + write = true; } write_arg = write_arg || (arg == Argument::True); }, diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs index e527adbb892..b6af4175edf 100644 --- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::sugg::Sugg; use clippy_utils::ty::is_type_diagnostic_item; use clippy_utils::usage::contains_return_break_continue_macro; -use clippy_utils::{eager_or_lazy, get_enclosing_block, in_macro, is_lang_ctor}; +use clippy_utils::{eager_or_lazy, in_macro, is_else_clause, is_lang_ctor}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::LangItem::OptionSome; @@ -81,7 +81,6 @@ struct OptionIfLetElseOccurence { method_sugg: String, some_expr: String, none_expr: String, - wrap_braces: bool, } /// Extracts the body of a given arm. If the arm contains only an expression, @@ -106,37 +105,6 @@ fn extract_body_from_arm<'a>(arm: &'a Arm<'a>) -> Option<&'a Expr<'a>> { } } -/// If this is the else body of an if/else expression, then we need to wrap -/// it in curly braces. Otherwise, we don't. -fn should_wrap_in_braces(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - get_enclosing_block(cx, expr.hir_id).map_or(false, |parent| { - let mut should_wrap = false; - - if let Some(Expr { - kind: - ExprKind::Match( - _, - arms, - MatchSource::IfLetDesugar { - contains_else_clause: true, - }, - ), - .. - }) = parent.expr - { - should_wrap = expr.hir_id == arms[1].body.hir_id; - } else if let Some(Expr { - kind: ExprKind::If(_, _, Some(else_clause)), - .. - }) = parent.expr - { - should_wrap = expr.hir_id == else_clause.hir_id; - } - - should_wrap - }) -} - fn format_option_in_sugg(cx: &LateContext<'_>, cond_expr: &Expr<'_>, as_ref: bool, as_mut: bool) -> String { format!( "{}{}", @@ -161,6 +129,7 @@ fn detect_option_if_let_else<'tcx>( if_chain! { if !in_macro(expr.span); // Don't lint macros, because it behaves weirdly if let ExprKind::Match(cond_expr, arms, MatchSource::IfLetDesugar{contains_else_clause: true}) = &expr.kind; + if !is_else_clause(cx.tcx, expr); if arms.len() == 2; if !is_result_ok(cx, cond_expr); // Don't lint on Result::ok because a different lint does it already if let PatKind::TupleStruct(struct_qpath, &[inner_pat], _) = &arms[0].pat.kind; @@ -168,13 +137,13 @@ fn detect_option_if_let_else<'tcx>( if let PatKind::Binding(bind_annotation, _, id, _) = &inner_pat.kind; if !contains_return_break_continue_macro(arms[0].body); if !contains_return_break_continue_macro(arms[1].body); + then { let capture_mut = if bind_annotation == &BindingAnnotation::Mutable { "mut " } else { "" }; let some_body = extract_body_from_arm(&arms[0])?; let none_body = extract_body_from_arm(&arms[1])?; let method_sugg = if eager_or_lazy::is_eagerness_candidate(cx, none_body) { "map_or" } else { "map_or_else" }; let capture_name = id.name.to_ident_string(); - let wrap_braces = should_wrap_in_braces(cx, expr); let (as_ref, as_mut) = match &cond_expr.kind { ExprKind::AddrOf(_, Mutability::Not, _) => (true, false), ExprKind::AddrOf(_, Mutability::Mut, _) => (false, true), @@ -190,7 +159,6 @@ fn detect_option_if_let_else<'tcx>( method_sugg: method_sugg.to_string(), some_expr: format!("|{}{}| {}", capture_mut, capture_name, Sugg::hir(cx, some_body, "..")), none_expr: format!("{}{}", if method_sugg == "map_or" { "" } else { "|| " }, Sugg::hir(cx, none_body, "..")), - wrap_braces, }) } else { None @@ -208,13 +176,8 @@ impl<'tcx> LateLintPass<'tcx> for OptionIfLetElse { format!("use Option::{} instead of an if let/else", detection.method_sugg).as_str(), "try", format!( - "{}{}.{}({}, {}){}", - if detection.wrap_braces { "{ " } else { "" }, - detection.option, - detection.method_sugg, - detection.none_expr, - detection.some_expr, - if detection.wrap_braces { " }" } else { "" }, + "{}.{}({}, {})", + detection.option, detection.method_sugg, detection.none_expr, detection.some_expr, ), Applicability::MaybeIncorrect, ); diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index 6b64846c24d..f6a70478559 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -102,10 +102,16 @@ declare_clippy_lint! { pub struct PassByRefOrValue { ref_min_size: u64, value_max_size: u64, + avoid_breaking_exported_api: bool, } impl<'tcx> PassByRefOrValue { - pub fn new(ref_min_size: Option<u64>, value_max_size: u64, target: &Target) -> Self { + pub fn new( + ref_min_size: Option<u64>, + value_max_size: u64, + avoid_breaking_exported_api: bool, + target: &Target, + ) -> Self { let ref_min_size = ref_min_size.unwrap_or_else(|| { let bit_width = u64::from(target.pointer_width); // Cap the calculated bit width at 32-bits to reduce @@ -120,10 +126,14 @@ impl<'tcx> PassByRefOrValue { Self { ref_min_size, value_max_size, + avoid_breaking_exported_api, } } fn check_poly_fn(&mut self, cx: &LateContext<'tcx>, hir_id: HirId, decl: &FnDecl<'_>, span: Option<Span>) { + if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) { + return; + } let fn_def_id = cx.tcx.hir().local_def_id(hir_id); let fn_sig = cx.tcx.fn_sig(fn_def_id); @@ -184,7 +194,6 @@ impl<'tcx> PassByRefOrValue { } if_chain! { - if !cx.access_levels.is_exported(hir_id); if is_copy(cx, ty); if !is_self_ty(input); if let Some(size) = cx.layout_of(ty).ok().map(|l| l.size.bytes()); diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index b0674f90678..12c44436874 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -211,7 +211,7 @@ fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { ]; if_chain! { - if let ExprKind::Call(ref fun, ref args) = expr.kind; + if let ExprKind::Call(fun, args) = expr.kind; if let ExprKind::Path(ref qpath) = fun.kind; if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::<Vec<_>>(); diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs index 30bee213900..d66bac52243 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark.rs @@ -88,7 +88,7 @@ impl QuestionMark { "replace it with", replacement_str, applicability, - ) + ); } } } @@ -129,7 +129,7 @@ impl QuestionMark { "replace it with", replacement, applicability, - ) + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index 7169f96eaf1..ae5f0627fd6 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability}; use clippy_utils::sugg::Sugg; 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 92921bedf4d..8f56a21ac5b 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs @@ -57,7 +57,7 @@ impl<'ast> ast_visit::Visitor<'ast> for ReturnVisitor { self.found_return = true; } - ast_visit::walk_expr(self, ex) + ast_visit::walk_expr(self, ex); } } diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs index e091095de13..05f9e01acb4 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantPubCrate { Applicability::MachineApplicable, ); }, - ) + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index 4b5306de58e..75151167454 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; use clippy_utils::{match_def_path, paths}; use if_chain::if_chain; diff --git a/src/tools/clippy/clippy_lints/src/repeat_once.rs b/src/tools/clippy/clippy_lints/src/repeat_once.rs index 560a5e7c920..b479c40bca6 100644 --- a/src/tools/clippy/clippy_lints/src/repeat_once.rs +++ b/src/tools/clippy/clippy_lints/src/repeat_once.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant_context, Constant}; +use clippy_utils::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::in_macro; use clippy_utils::source::snippet; diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index b565c77aaec..251d527c265 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -139,7 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for Return { } else { RetReplacement::Empty }; - check_final_expr(cx, &body.value, Some(body.value.span), replacement) + check_final_expr(cx, &body.value, Some(body.value.span), replacement); }, FnKind::ItemFn(..) | FnKind::Method(..) => { if let ExprKind::Block(block, _) = body.value.kind { @@ -241,7 +241,7 @@ fn emit_return_lint(cx: &LateContext<'_>, ret_span: Span, inner_span: Option<Spa if let Some(snippet) = snippet_opt(cx, inner_span) { diag.span_suggestion(ret_span, "remove `return`", snippet, Applicability::MachineApplicable); } - }) + }); }, None => match replacement { RetReplacement::Empty => { diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs index 553987a426b..16e4d73851f 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs @@ -8,11 +8,11 @@ use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// **What it does:** Looks for blocks of expressions and fires if the last expression returns `()` - /// but is not followed by a semicolon. + /// **What it does:** Looks for blocks of expressions and fires if the last expression returns + /// `()` but is not followed by a semicolon. /// - /// **Why is this bad?** The semicolon might be optional but when - /// extending the block with new code, it doesn't require a change in previous last line. + /// **Why is this bad?** The semicolon might be optional but when extending the block with new + /// code, it doesn't require a change in previous last line. /// /// **Known problems:** None. /// @@ -30,7 +30,7 @@ declare_clippy_lint! { /// } /// ``` pub SEMICOLON_IF_NOTHING_RETURNED, - restriction, + pedantic, "add a semicolon if nothing is returned" } diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index d6101bd5e36..ac3f7ebd14b 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -120,7 +120,7 @@ fn check_fn<'tcx>(cx: &LateContext<'tcx>, decl: &'tcx FnDecl<'_>, body: &'tcx Bo let mut bindings = Vec::with_capacity(decl.inputs.len()); for arg in iter_input_pats(decl, body) { if let PatKind::Binding(.., ident, _) = arg.pat.kind { - bindings.push((ident.name, ident.span)) + bindings.push((ident.name, ident.span)); } } check_expr(cx, &body.value, &mut bindings); @@ -156,7 +156,7 @@ fn check_local<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>, bindings: & .. } = *local; if let Some(t) = *ty { - check_ty(cx, t, bindings) + check_ty(cx, t, bindings); } if let Some(o) = *init { check_expr(cx, o, bindings); @@ -324,14 +324,14 @@ fn check_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, bindings: &mut } match expr.kind { ExprKind::Unary(_, e) | ExprKind::Field(e, _) | ExprKind::AddrOf(_, _, e) | ExprKind::Box(e) => { - check_expr(cx, e, bindings) + check_expr(cx, e, bindings); }, ExprKind::Block(block, _) | ExprKind::Loop(block, ..) => check_block(cx, block, bindings), // ExprKind::Call // ExprKind::MethodCall ExprKind::Array(v) | ExprKind::Tup(v) => { for e in v { - check_expr(cx, e, bindings) + check_expr(cx, e, bindings); } }, ExprKind::If(cond, then, ref otherwise) => { @@ -374,7 +374,7 @@ fn check_ty<'tcx>(cx: &LateContext<'tcx>, ty: &'tcx Ty<'_>, bindings: &mut Vec<( TyKind::Ptr(MutTy { ty: mty, .. }) | TyKind::Rptr(_, MutTy { ty: mty, .. }) => check_ty(cx, mty, bindings), TyKind::Tup(tup) => { for t in tup { - check_ty(cx, t, bindings) + check_ty(cx, t, bindings); } }, TyKind::Typeof(ref anon_const) => check_expr(cx, &cx.tcx.hir().body(anon_const.body).value, bindings), diff --git a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs index a45bb102389..1eaad438237 100644 --- a/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs +++ b/src/tools/clippy/clippy_lints/src/single_component_path_imports.rs @@ -70,7 +70,7 @@ fn check_mod(cx: &EarlyContext<'_>, items: &[P<Item>]) { for item in items { track_uses( cx, - &item, + item, &mut imports_reused_with_self, &mut single_use_usages, &mut macros, @@ -117,7 +117,7 @@ fn track_uses( match &item.kind { ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) => { - check_mod(cx, &items); + check_mod(cx, items); }, ItemKind::MacroDef(MacroDef { macro_rules: true, .. }) => { macros.push(item.ident.name); 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 a9ae2b77119..e5c58d70b60 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -158,7 +158,7 @@ impl SlowVectorInit { ) { match initialization { InitializationType::Extend(e) | InitializationType::Resize(e) => { - Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization") + Self::emit_lint(cx, e, vec_alloc, "slow zero-filling initialization"); }, }; } @@ -290,7 +290,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> { fn visit_block(&mut self, block: &'tcx Block<'_>) { if self.initialization_found { if let Some(s) = block.stmts.get(0) { - self.visit_stmt(s) + self.visit_stmt(s); } self.initialization_found = false; 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 4272935bc31..bb707f78fcc 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -59,7 +59,7 @@ declare_clippy_lint! { /// } /// ``` pub SUSPICIOUS_OPERATION_GROUPINGS, - style, + nursery, "groupings of binary operations that look suspiciously like typos" } @@ -266,7 +266,7 @@ fn emit_suggestion(cx: &EarlyContext<'_>, span: Span, sugg: String, applicabilit "did you mean", sugg, applicability, - ) + ); } fn ident_swap_sugg( @@ -475,7 +475,7 @@ impl Add for IdentLocation { impl AddAssign for IdentLocation { fn add_assign(&mut self, other: Self) { - *self = *self + other + *self = *self + other; } } @@ -506,7 +506,7 @@ impl Add for IdentDifference { impl AddAssign for IdentDifference { fn add_assign(&mut self, other: Self) { - *self = *self + other + *self = *self + other; } } diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index b0589b0512e..74a94db1800 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -3,6 +3,7 @@ use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::{in_macro, SpanlessHash}; use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::unhash::UnhashMap; use rustc_errors::Applicability; use rustc_hir::{def::Res, GenericBound, Generics, ParamName, Path, QPath, TyKind, WherePredicate}; use rustc_lint::{LateContext, LateLintPass}; @@ -100,7 +101,7 @@ impl TraitBounds { hasher.hash_ty(ty); hasher.finish() }; - let mut map = FxHashMap::default(); + let mut map: UnhashMap<u64, Vec<&GenericBound<'_>>> = UnhashMap::default(); let mut applicability = Applicability::MaybeIncorrect; for bound in gen.where_clause.predicates { if_chain! { diff --git a/src/tools/clippy/clippy_lints/src/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmuting_null.rs index 888ecab1046..b57d158293d 100644 --- a/src/tools/clippy/clippy_lints/src/transmuting_null.rs +++ b/src/tools/clippy/clippy_lints/src/transmuting_null.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant_context, Constant}; +use clippy_utils::consts::{constant_context, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{is_expr_path_def_path, paths}; use if_chain::if_chain; diff --git a/src/tools/clippy/clippy_lints/src/try_err.rs b/src/tools/clippy/clippy_lints/src/try_err.rs index ebb39ea4877..f2ba2b2ecf6 100644 --- a/src/tools/clippy/clippy_lints/src/try_err.rs +++ b/src/tools/clippy/clippy_lints/src/try_err.rs @@ -64,7 +64,7 @@ impl<'tcx> LateLintPass<'tcx> for TryErr { if let ExprKind::Match(match_arg, _, MatchSource::TryDesugar) = expr.kind; if let ExprKind::Call(match_fun, try_args) = match_arg.kind; if let ExprKind::Path(ref match_fun_path) = match_fun.kind; - if matches!(match_fun_path, QPath::LangItem(LangItem::TryIntoResult, _)); + 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); diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index d9b47a699dc..70b9e8adef8 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -306,7 +306,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { fn check_trait_item(&mut self, cx: &LateContext<'_>, item: &TraitItem<'_>) { match item.kind { TraitItemKind::Const(ty, _) | TraitItemKind::Type(_, Some(ty)) => { - self.check_ty(cx, ty, CheckTyContext::default()) + self.check_ty(cx, ty, CheckTyContext::default()); }, TraitItemKind::Fn(ref sig, _) => self.check_fn_decl(cx, sig.decl, CheckTyContext::default()), TraitItemKind::Type(..) => (), @@ -433,7 +433,7 @@ impl Types { }, TyKind::Slice(ty) | TyKind::Array(ty, _) | TyKind::Ptr(MutTy { ty, .. }) => { context.is_nested_call = true; - self.check_ty(cx, ty, context) + self.check_ty(cx, ty, context); }, TyKind::Tup(tys) => { context.is_nested_call = true; diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs index d81e31f5a21..45291a120ed 100644 --- a/src/tools/clippy/clippy_lints/src/unicode.rs +++ b/src/tools/clippy/clippy_lints/src/unicode.rs @@ -71,7 +71,7 @@ impl LateLintPass<'_> for Unicode { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { if let ExprKind::Lit(ref lit) = expr.kind { if let LitKind::Str(_, _) = lit.node { - check_str(cx, lit.span, expr.hir_id) + check_str(cx, lit.span, expr.hir_id); } } } @@ -82,7 +82,7 @@ fn escape<T: Iterator<Item = char>>(s: T) -> String { for c in s { if c as u32 > 0x7F { for d in c.escape_unicode() { - result.push(d) + result.push(d); } } else { result.push(c); diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs index d22f7d9a96b..04542146516 100644 --- a/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_cmp.rs @@ -8,7 +8,12 @@ use super::UNIT_CMP; pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) { if expr.span.from_expansion() { if let Some(callee) = expr.span.source_callee() { - if let ExpnKind::Macro { kind: MacroKind::Bang, name: symbol, proc_macro: _ } = callee.kind { + if let ExpnKind::Macro { + kind: MacroKind::Bang, + name: symbol, + proc_macro: _, + } = callee.kind + { if let ExprKind::Binary(ref cmp, left, _) = expr.kind { let op = cmp.node; if op.is_comparison() && cx.typeck_results().expr_ty(left).is_unit() { diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index f2f1410aed7..a85ffa6aa95 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -8,7 +8,7 @@ use rustc_hir::LangItem::{OptionSome, ResultOk}; use rustc_hir::{Body, ExprKind, FnDecl, HirId, Impl, ItemKind, Node}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::sym; use rustc_span::Span; @@ -52,7 +52,19 @@ declare_clippy_lint! { "functions that only return `Ok` or `Some`" } -declare_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]); +pub struct UnnecessaryWraps { + avoid_breaking_exported_api: bool, +} + +impl_lint_pass!(UnnecessaryWraps => [UNNECESSARY_WRAPS]); + +impl UnnecessaryWraps { + pub fn new(avoid_breaking_exported_api: bool) -> Self { + Self { + avoid_breaking_exported_api, + } + } +} impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { fn check_fn( @@ -66,13 +78,12 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { ) { // Abort if public function/method or closure. match fn_kind { - FnKind::ItemFn(.., visibility) | FnKind::Method(.., Some(visibility)) => { - if visibility.node.is_pub() { + FnKind::ItemFn(..) | FnKind::Method(..) => { + if self.avoid_breaking_exported_api && cx.access_levels.is_exported(hir_id) { return; } }, FnKind::Closure => return, - FnKind::Method(..) => (), } // Abort if the method is implementing a trait or of it a trait method. diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs new file mode 100644 index 00000000000..18ee07d3a95 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -0,0 +1,92 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_hir::intravisit::{walk_expr, walk_fn, FnKind, NestedVisitorMap, Visitor}; +use rustc_hir::{Body, Expr, ExprKind, FnDecl, FnHeader, HirId, IsAsync, Item, ItemKind, YieldSource}; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::hir::map::Map; +use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::Span; + +declare_clippy_lint! { + /// **What it does:** Checks for functions that are declared `async` but have no `.await`s inside of them. + /// + /// **Why is this bad?** Async functions with no async code create overhead, both mentally and computationally. + /// Callers of async methods either need to be calling from an async function themselves or run it on an executor, both of which + /// causes runtime overhead and hassle for the caller. + /// + /// **Known problems:** None + /// + /// **Example:** + /// + /// ```rust + /// // Bad + /// async fn get_random_number() -> i64 { + /// 4 // Chosen by fair dice roll. Guaranteed to be random. + /// } + /// let number_future = get_random_number(); + /// + /// // Good + /// fn get_random_number_improved() -> i64 { + /// 4 // Chosen by fair dice roll. Guaranteed to be random. + /// } + /// let number_future = async { get_random_number_improved() }; + /// ``` + pub UNUSED_ASYNC, + pedantic, + "finds async functions with no await statements" +} + +declare_lint_pass!(UnusedAsync => [UNUSED_ASYNC]); + +struct AsyncFnVisitor<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + found_await: bool, +} + +impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> { + type Map = Map<'tcx>; + + fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { + if let ExprKind::Yield(_, YieldSource::Await { .. }) = ex.kind { + self.found_await = true; + } + walk_expr(self, ex); + } + + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } +} + +impl<'tcx> LateLintPass<'tcx> for UnusedAsync { + fn check_item(&mut self, _: &LateContext<'tcx>, item: &'tcx Item<'tcx>) { + if let ItemKind::Trait(..) = item.kind { + return; + } + } + fn check_fn( + &mut self, + cx: &LateContext<'tcx>, + fn_kind: FnKind<'tcx>, + fn_decl: &'tcx FnDecl<'tcx>, + body: &Body<'tcx>, + span: Span, + hir_id: HirId, + ) { + if let FnKind::ItemFn(_, _, FnHeader { asyncness, .. }, _) = &fn_kind { + if matches!(asyncness, IsAsync::Async) { + let mut visitor = AsyncFnVisitor { cx, found_await: false }; + walk_fn(&mut visitor, fn_kind, fn_decl, body.id(), span, hir_id); + if !visitor.found_await { + span_lint_and_help( + cx, + UNUSED_ASYNC, + span, + "unused `async` for function with no await statements", + None, + "consider removing the `async` from this function", + ); + } + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs index 3387f35bac3..ee082d30d93 100644 --- a/src/tools/clippy/clippy_lints/src/unused_io_amount.rs +++ b/src/tools/clippy/clippy_lints/src/unused_io_amount.rs @@ -45,7 +45,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { if let hir::ExprKind::Call(func, args) = res.kind { if matches!( func.kind, - hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryIntoResult, _)) + hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::TryTraitBranch, _)) ) { check_map_error(cx, &args[0], expr); } @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedIoAmount { fn check_map_error(cx: &LateContext<'_>, call: &hir::Expr<'_>, expr: &hir::Expr<'_>) { let mut call = call; - while let hir::ExprKind::MethodCall(ref path, _, ref args, _) = call.kind { + while let hir::ExprKind::MethodCall(path, _, args, _) = call.kind { if matches!(&*path.ident.as_str(), "or" | "or_else" | "ok") { call = &args[0]; } else { diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs index 4ac2ec55b98..0b58c6c0917 100644 --- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs +++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs @@ -1,8 +1,8 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use itertools::Itertools; -use rustc_ast::ast::{Item, ItemKind, VisibilityKind}; use rustc_errors::Applicability; -use rustc_lint::{EarlyContext, EarlyLintPass, LintContext}; +use rustc_hir::{Item, ItemKind}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::Ident; @@ -38,12 +38,14 @@ declare_clippy_lint! { #[derive(Default)] pub struct UpperCaseAcronyms { + avoid_breaking_exported_api: bool, upper_case_acronyms_aggressive: bool, } impl UpperCaseAcronyms { - pub fn new(aggressive: bool) -> Self { + pub fn new(avoid_breaking_exported_api: bool, aggressive: bool) -> Self { Self { + avoid_breaking_exported_api, upper_case_acronyms_aggressive: aggressive, } } @@ -72,7 +74,7 @@ fn correct_ident(ident: &str) -> String { ident } -fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) { +fn check_ident(cx: &LateContext<'_>, ident: &Ident, be_aggressive: bool) { let span = ident.span; let ident = &ident.as_str(); let corrected = correct_ident(ident); @@ -92,27 +94,31 @@ fn check_ident(cx: &EarlyContext<'_>, ident: &Ident, be_aggressive: bool) { "consider making the acronym lowercase, except the initial letter", corrected, Applicability::MaybeIncorrect, - ) + ); } } -impl EarlyLintPass for UpperCaseAcronyms { - fn check_item(&mut self, cx: &EarlyContext<'_>, it: &Item) { +impl LateLintPass<'_> for UpperCaseAcronyms { + fn check_item(&mut self, cx: &LateContext<'_>, it: &Item<'_>) { // do not lint public items or in macros - if !in_external_macro(cx.sess(), it.span) && !matches!(it.vis.kind, VisibilityKind::Public) { - if matches!( - it.kind, - ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..) - ) { + if in_external_macro(cx.sess(), it.span) + || (self.avoid_breaking_exported_api && cx.access_levels.is_exported(it.hir_id())) + { + return; + } + match it.kind { + ItemKind::TyAlias(..) | ItemKind::Struct(..) | ItemKind::Trait(..) => { check_ident(cx, &it.ident, self.upper_case_acronyms_aggressive); - } else if let ItemKind::Enum(ref enumdef, _) = it.kind { + }, + ItemKind::Enum(ref enumdef, _) => { // check enum variants seperately because again we only want to lint on private enums and // the fn check_variant does not know about the vis of the enum of its variants enumdef .variants .iter() .for_each(|variant| check_ident(cx, &variant.ident, self.upper_case_acronyms_aggressive)); - } + }, + _ => {}, } } } diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs index aa4d16633ff..254b104bdef 100644 --- a/src/tools/clippy/clippy_lints/src/use_self.rs +++ b/src/tools/clippy/clippy_lints/src/use_self.rs @@ -1,12 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_opt; +use clippy_utils::ty::same_type_and_consts; use clippy_utils::{in_macro, meets_msrv, msrvs}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir as hir; -use rustc_hir::def::DefKind; use rustc_hir::{ - def, + self as hir, + def::{self, DefKind}, def_id::LocalDefId, intravisit::{walk_ty, NestedVisitorMap, Visitor}, Expr, ExprKind, FnRetTy, FnSig, GenericArg, HirId, Impl, ImplItemKind, Item, ItemKind, Node, Path, PathSegment, @@ -14,7 +14,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::hir::map::Map; -use rustc_middle::ty::{AssocKind, Ty, TyS}; +use rustc_middle::ty::{AssocKind, Ty}; use rustc_semver::RustcVersion; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{BytePos, Span}; @@ -356,7 +356,7 @@ impl<'tcx> Visitor<'tcx> for SkipTyCollector { fn visit_ty(&mut self, hir_ty: &hir::Ty<'_>) { self.types_to_skip.push(hir_ty.hir_id); - walk_ty(self, hir_ty) + walk_ty(self, hir_ty); } fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { @@ -385,7 +385,7 @@ impl<'a, 'tcx> Visitor<'tcx> for LintTyCollector<'a, 'tcx> { } } - walk_ty(self, hir_ty) + walk_ty(self, hir_ty); } fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { @@ -459,7 +459,7 @@ fn in_impl(cx: &LateContext<'tcx>, hir_ty: &hir::Ty<'_>) -> bool { fn should_lint_ty(hir_ty: &hir::Ty<'_>, ty: Ty<'_>, self_ty: Ty<'_>) -> bool { if_chain! { - if TyS::same_type(ty, self_ty); + if same_type_and_consts(ty, self_ty); if let TyKind::Path(QPath::Resolved(_, path)) = hir_ty.kind; then { !matches!(path.res, def::Res::SelfTy(..)) diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 7edb280be73..2be99fb761b 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -1,13 +1,13 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; use clippy_utils::source::{snippet, snippet_with_macro_callsite}; use clippy_utils::sugg::Sugg; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{get_parent_expr, match_def_path, match_trait_method, paths}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind, HirId, MatchSource}; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, TyS}; +use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::sym; @@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if match_trait_method(cx, e, &paths::INTO) && &*name.ident.as_str() == "into" { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(&args[0]); - if TyS::same_type(a, b) { + if same_type_and_consts(a, b) { let sugg = snippet_with_macro_callsite(cx, args[0].span, "<expr>").to_string(); span_lint_and_sugg( cx, @@ -90,7 +90,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { } let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(&args[0]); - if TyS::same_type(a, b) { + if same_type_and_consts(a, b) { let sugg = snippet(cx, args[0].span, "<expr>").into_owned(); span_lint_and_sugg( cx, @@ -110,7 +110,8 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if is_type_diagnostic_item(cx, a, sym::result_type); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); - if TyS::same_type(a_type, b); + if same_type_and_consts(a_type, b); + then { span_lint_and_help( cx, @@ -137,7 +138,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if is_type_diagnostic_item(cx, a, sym::result_type); if let ty::Adt(_, substs) = a.kind(); if let Some(a_type) = substs.types().next(); - if TyS::same_type(a_type, b); + if same_type_and_consts(a_type, b); then { let hint = format!("consider removing `{}()`", snippet(cx, path.span, "TryFrom::try_from")); @@ -154,7 +155,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if_chain! { if match_def_path(cx, def_id, &paths::FROM_FROM); - if TyS::same_type(a, b); + if same_type_and_consts(a, b); then { let sugg = Sugg::hir_with_macro_callsite(cx, &args[0], "<expr>").maybe_par(); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index e70f8a09ebe..39ef170ae36 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -292,7 +292,7 @@ impl<'tcx> Visitor<'tcx> for PrintVisitor { LitKind::Str(ref text, _) => { let str_pat = self.next("s"); println!(" if let LitKind::Str(ref {}, _) = {}.node;", str_pat, lit_pat); - println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str()) + println!(" if {}.as_str() == {:?}", str_pat, &*text.as_str()); }, } }, diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index 52c1dc3bdd2..0e33ae740d9 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -26,13 +26,13 @@ impl TryConf { macro_rules! define_Conf { ($( - #[$doc:meta] + #[doc = $doc:literal] $(#[conf_deprecated($dep:literal)])? ($name:ident: $ty:ty = $default:expr), )*) => { /// Clippy lint configuration pub struct Conf { - $(#[$doc] pub $name: $ty,)* + $(#[doc = $doc] pub $name: $ty,)* } mod defaults { @@ -89,12 +89,42 @@ macro_rules! define_Conf { Ok(TryConf { conf, errors }) } } + + #[cfg(feature = "metadata-collector-lint")] + pub mod metadata { + use crate::utils::internal_lints::metadata_collector::ClippyConfiguration; + + macro_rules! wrap_option { + () => (None); + ($x:literal) => (Some($x)); + } + + pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> { + vec![ + $( + { + let deprecation_reason = wrap_option!($($dep)?); + + ClippyConfiguration::new( + stringify!($name), + stringify!($ty), + format!("{:?}", super::defaults::$name()), + $doc, + deprecation_reason, + ) + }, + )+ + ] + } + } }; } // N.B., this macro is parsed by util/lintlib.py define_Conf! { - /// Lint: CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports + /// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION. Suppress lints whenever the suggested change would cause breakage for other crates. + (avoid_breaking_exported_api: bool = true), + /// Lint: MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE. The minimum rust version that the project supports (msrv: Option<String> = None), /// Lint: BLACKLISTED_NAME. The list of blacklisted names to lint about. NB: `bar` is not here since it has legitimate uses (blacklisted_names: Vec<String> = ["foo", "baz", "quux"].iter().map(ToString::to_string).collect()), @@ -180,15 +210,13 @@ pub fn lookup_conf_file() -> io::Result<Option<PathBuf>> { .map_or_else(|| PathBuf::from("."), PathBuf::from); loop { for config_file_name in &CONFIG_FILE_NAMES { - let config_file = current.join(config_file_name); - match fs::metadata(&config_file) { - // Only return if it's a file to handle the unlikely situation of a directory named - // `clippy.toml`. - Ok(ref md) if !md.is_dir() => return Ok(Some(config_file)), - // Return the error if it's something other than `NotFound`; otherwise we didn't - // find the project file yet, and continue searching. - Err(e) if e.kind() != io::ErrorKind::NotFound => return Err(e), - _ => {}, + if let Ok(config_file) = current.join(config_file_name).canonicalize() { + match fs::metadata(&config_file) { + Err(e) if e.kind() == io::ErrorKind::NotFound => {}, + Err(e) => return Err(e), + Ok(md) if md.is_dir() => {}, + Ok(_) => return Ok(Some(config_file)), + } } } 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 ee7be24eae8..b1523e032af 100644 --- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs +++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant_simple, Constant}; +use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then}; use clippy_utils::source::snippet; use clippy_utils::ty::match_type; @@ -1100,7 +1100,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle { IF_CHAIN_STYLE, if_chain_local_span(cx, local, if_chain_span), "`let` expression should be inside `then { .. }`", - ) + ); } } @@ -1141,7 +1141,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle { if is_first_if_chain_expr(cx, expr.hir_id, if_chain_span) && is_if_chain_then(then_block.stmts, then_block.expr, if_chain_span) { - span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`") + span_lint(cx, IF_CHAIN_STYLE, expr.span, "`if_chain!` only has one `if`"); } } } 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 e85637ca758..46af03663b8 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 @@ -8,9 +8,6 @@ //! during any comparison or mapping. (Please take care of this, it's not fun to spend time on such //! a simple mistake) -// # NITs -// - TODO xFrednet 2021-02-13: Collect depreciations and maybe renames - use if_chain::if_chain; use rustc_data_structures::fx::FxHashMap; use rustc_hir::{ @@ -22,13 +19,14 @@ use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::{sym, Loc, Span, Symbol}; use serde::{ser::SerializeStruct, Serialize, Serializer}; use std::collections::BinaryHeap; +use std::fmt; use std::fs::{self, OpenOptions}; use std::io::prelude::*; use std::path::Path; use crate::utils::internal_lints::is_lint_ref_type; use clippy_utils::{ - diagnostics::span_lint, last_path_segment, match_function_call, match_path, paths, ty::match_type, + diagnostics::span_lint, last_path_segment, match_def_path, match_function_call, match_path, paths, ty::match_type, ty::walk_ptrs_ty_depth, }; @@ -39,8 +37,52 @@ const BLACK_LISTED_LINTS: [&str; 3] = ["lint_author", "deep_code_inspection", "i /// These groups will be ignored by the lint group matcher. This is useful for collections like /// `clippy::all` const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"]; -/// Lints within this group will be excluded from the collection -const EXCLUDED_LINT_GROUPS: [&str; 1] = ["clippy::internal"]; +/// Lints within this group will be excluded from the collection. These groups +/// have to be defined without the `clippy::` prefix. +const EXCLUDED_LINT_GROUPS: [&str; 1] = ["internal"]; +/// Collected deprecated lint will be assigned to this group in the JSON output +const DEPRECATED_LINT_GROUP_STR: &str = "deprecated"; +/// This is the lint level for deprecated lints that will be displayed in the lint list +const DEPRECATED_LINT_LEVEL: &str = "none"; +/// This array holds Clippy's lint groups with their corresponding default lint level. The +/// lint level for deprecated lints is set in `DEPRECATED_LINT_LEVEL`. +const DEFAULT_LINT_LEVELS: [(&str, &str); 8] = [ + ("correctness", "deny"), + ("restriction", "allow"), + ("style", "warn"), + ("pedantic", "allow"), + ("complexity", "warn"), + ("perf", "warn"), + ("cargo", "allow"), + ("nursery", "allow"), +]; +/// This prefix is in front of the lint groups in the lint store. The prefix will be trimmed +/// to only keep the actual lint group in the output. +const CLIPPY_LINT_GROUP_PREFIX: &str = "clippy::"; + +/// This template will be used to format the configuration section in the lint documentation. +/// The `configurations` parameter will be replaced with one or multiple formatted +/// `ClippyConfiguration` instances. See `CONFIGURATION_VALUE_TEMPLATE` for further customizations +macro_rules! CONFIGURATION_SECTION_TEMPLATE { + () => { + r#" +**Configuration** +This lint has the following configuration variables: + +{configurations} +"# + }; +} +/// This template will be used to format an individual `ClippyConfiguration` instance in the +/// lint documentation. +/// +/// The format function will provide strings for the following parameters: `name`, `ty`, `doc` and +/// `default` +macro_rules! CONFIGURATION_VALUE_TEMPLATE { + () => { + "* {name}: {ty}: {doc} (defaults to `{default}`)\n" + }; +} const LINT_EMISSION_FUNCTIONS: [&[&str]; 7] = [ &["clippy_utils", "diagnostics", "span_lint"], @@ -66,6 +108,7 @@ const SUGGESTION_FUNCTIONS: [&[&str]; 2] = [ &["clippy_utils", "diagnostics", "multispan_sugg"], &["clippy_utils", "diagnostics", "multispan_sugg_with_applicability"], ]; +const DEPRECATED_LINT_TYPE: [&str; 3] = ["clippy_lints", "deprecated_lints", "ClippyDeprecatedLint"]; /// The index of the applicability name of `paths::APPLICABILITY_VALUES` const APPLICABILITY_NAME_INDEX: usize = 2; @@ -102,13 +145,33 @@ declare_clippy_lint! { impl_lint_pass!(MetadataCollector => [INTERNAL_METADATA_COLLECTOR]); #[allow(clippy::module_name_repetitions)] -#[derive(Debug, Clone, Default)] +#[derive(Debug, Clone)] pub struct MetadataCollector { /// All collected lints /// /// We use a Heap here to have the lints added in alphabetic order in the export lints: BinaryHeap<LintMetadata>, applicability_info: FxHashMap<String, ApplicabilityInfo>, + config: Vec<ClippyConfiguration>, +} + +impl MetadataCollector { + pub fn new() -> Self { + Self { + lints: BinaryHeap::<LintMetadata>::default(), + applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(), + config: collect_configs(), + } + } + + fn get_lint_configs(&self, lint_name: &str) -> Option<String> { + self.config + .iter() + .filter(|config| config.lints.iter().any(|lint| lint == lint_name)) + .map(ToString::to_string) + .reduce(|acc, x| acc + &x) + .map(|configurations| format!(CONFIGURATION_SECTION_TEMPLATE!(), configurations = configurations)) + } } impl Drop for MetadataCollector { @@ -143,6 +206,7 @@ struct LintMetadata { id: String, id_span: SerializableSpan, group: String, + level: &'static str, docs: String, /// This field is only used in the output and will only be /// mapped shortly before the actual output. @@ -150,11 +214,12 @@ struct LintMetadata { } impl LintMetadata { - fn new(id: String, id_span: SerializableSpan, group: String, docs: String) -> Self { + fn new(id: String, id_span: SerializableSpan, group: String, level: &'static str, docs: String) -> Self { Self { id, id_span, group, + level, docs, applicability: None, } @@ -182,7 +247,7 @@ impl SerializableSpan { let loc: Loc = cx.sess().source_map().lookup_char_pos(span.lo()); Self { - path: format!("{}", loc.file.name), + path: format!("{}", loc.file.name.prefer_remapped()), line: loc.line, } } @@ -214,6 +279,95 @@ impl Serialize for ApplicabilityInfo { } } +// ================================================================== +// Configuration +// ================================================================== +#[derive(Debug, Clone, Default)] +pub struct ClippyConfiguration { + name: String, + config_type: &'static str, + default: String, + lints: Vec<String>, + doc: String, + deprecation_reason: Option<&'static str>, +} + +impl ClippyConfiguration { + pub fn new( + name: &'static str, + config_type: &'static str, + default: String, + doc_comment: &'static str, + deprecation_reason: Option<&'static str>, + ) -> Self { + let (lints, doc) = parse_config_field_doc(doc_comment) + .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string())); + + Self { + name: to_kebab(name), + lints, + doc, + config_type, + default, + deprecation_reason, + } + } +} + +fn collect_configs() -> Vec<ClippyConfiguration> { + crate::utils::conf::metadata::get_configuration_metadata() +} + +/// This parses the field documentation of the config struct. +/// +/// ```rust, ignore +/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin") +/// ``` +/// +/// Would yield: +/// ```rust, ignore +/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin") +/// ``` +fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> { + const DOC_START: &str = " Lint: "; + if_chain! { + if doc_comment.starts_with(DOC_START); + if let Some(split_pos) = doc_comment.find('.'); + then { + let mut doc_comment = doc_comment.to_string(); + let documentation = doc_comment.split_off(split_pos); + + doc_comment.make_ascii_lowercase(); + let lints: Vec<String> = doc_comment.split_off(DOC_START.len()).split(", ").map(str::to_string).collect(); + + Some((lints, documentation)) + } else { + None + } + } +} + +/// Transforms a given `snake_case_string` to a tasty `kebab-case-string` +fn to_kebab(config_name: &str) -> String { + config_name.replace('_', "-") +} + +impl fmt::Display for ClippyConfiguration { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + CONFIGURATION_VALUE_TEMPLATE!(), + name = self.name, + ty = self.config_type, + doc = self.doc, + default = self.default + ) + } +} + +// ================================================================== +// Lint pass +// ================================================================== impl<'hir> LateLintPass<'hir> for MetadataCollector { /// Collecting lint declarations like: /// ```rust, ignore @@ -225,23 +379,48 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { /// } /// ``` fn check_item(&mut self, cx: &LateContext<'hir>, item: &'hir Item<'_>) { - if_chain! { - // item validation - if let ItemKind::Static(ref ty, Mutability::Not, _) = item.kind; - if is_lint_ref_type(cx, ty); - // blacklist check - let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); - if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); - // metadata extraction - if let Some(group) = get_lint_group_or_lint(cx, &lint_name, item); - if let Some(docs) = extract_attr_docs_or_lint(cx, item); - then { - self.lints.push(LintMetadata::new( - lint_name, - SerializableSpan::from_item(cx, item), - group, - docs, - )); + if let ItemKind::Static(ty, Mutability::Not, _) = item.kind { + // Normal lint + if_chain! { + // item validation + if is_lint_ref_type(cx, ty); + // blacklist check + let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase(); + if !BLACK_LISTED_LINTS.contains(&lint_name.as_str()); + // metadata extraction + if let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item); + if let Some(mut docs) = extract_attr_docs_or_lint(cx, item); + then { + if let Some(configuration_section) = self.get_lint_configs(&lint_name) { + docs.push_str(&configuration_section); + } + + self.lints.push(LintMetadata::new( + lint_name, + SerializableSpan::from_item(cx, item), + group, + level, + docs, + )); + } + } + + if_chain! { + if is_deprecated_lint(cx, ty); + // blacklist 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 + if let Some(docs) = extract_attr_docs_or_lint(cx, item); + then { + self.lints.push(LintMetadata::new( + lint_name, + SerializableSpan::from_item(cx, item), + DEPRECATED_LINT_GROUP_STR.to_string(), + DEPRECATED_LINT_LEVEL, + docs, + )); + } } } } @@ -268,7 +447,7 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector { // - src/misc.rs:734:9 // - src/methods/mod.rs:3545:13 // - src/methods/mod.rs:3496:13 - // We are basically unable to resolve the lint name it self. + // We are basically unable to resolve the lint name itself. return; } @@ -310,7 +489,7 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> { .hir() .attrs(item.hir_id()) .iter() - .filter_map(|ref x| x.doc_str().map(|sym| sym.as_str().to_string())) + .filter_map(|x| x.doc_str().map(|sym| sym.as_str().to_string())) .reduce(|mut acc, sym| { acc.push_str(&sym); acc.push('\n'); @@ -318,15 +497,32 @@ fn extract_attr_docs(cx: &LateContext<'_>, item: &Item<'_>) -> Option<String> { }) } -fn get_lint_group_or_lint(cx: &LateContext<'_>, lint_name: &str, item: &'hir Item<'_>) -> Option<String> { +fn get_lint_group_and_level_or_lint( + cx: &LateContext<'_>, + lint_name: &str, + item: &'hir Item<'_>, +) -> Option<(String, &'static str)> { let result = cx.lint_store.check_lint_name(lint_name, Some(sym::clippy)); if let CheckLintNameResult::Tool(Ok(lint_lst)) = result { - get_lint_group(cx, lint_lst[0]) - .or_else(|| { - lint_collection_error_item(cx, item, "Unable to determine lint group"); + if let Some(group) = get_lint_group(cx, lint_lst[0]) { + if EXCLUDED_LINT_GROUPS.contains(&group.as_str()) { + return None; + } + + if let Some(level) = get_lint_level_from_group(&group) { + Some((group, level)) + } else { + lint_collection_error_item( + cx, + item, + &format!("Unable to determine lint level for found group `{}`", group), + ); None - }) - .filter(|group| !EXCLUDED_LINT_GROUPS.contains(&group.as_str())) + } + } else { + lint_collection_error_item(cx, item, "Unable to determine lint group"); + None + } } else { lint_collection_error_item(cx, item, "Unable to find lint in lint_store"); None @@ -339,14 +535,31 @@ fn get_lint_group(cx: &LateContext<'_>, lint_id: LintId) -> Option<String> { continue; } - if lints.iter().any(|x| *x == lint_id) { - return Some((*group_name).to_string()); + if lints.iter().any(|group_lint| *group_lint == lint_id) { + let group = group_name.strip_prefix(CLIPPY_LINT_GROUP_PREFIX).unwrap_or(group_name); + return Some((*group).to_string()); } } None } +fn get_lint_level_from_group(lint_group: &str) -> Option<&'static str> { + DEFAULT_LINT_LEVELS + .iter() + .find_map(|(group_name, group_level)| (*group_name == lint_group).then(|| *group_level)) +} + +fn is_deprecated_lint(cx: &LateContext<'_>, ty: &hir::Ty<'_>) -> bool { + if let hir::TyKind::Path(ref path) = ty.kind { + if let hir::def::Res::Def(DefKind::Struct, def_id) = cx.qpath_res(path, ty.hir_id) { + return match_def_path(cx, def_id, &DEPRECATED_LINT_TYPE); + } + } + + false +} + // ================================================================== // Lint emission // ================================================================== @@ -383,7 +596,7 @@ fn extract_emission_info<'hir>( let mut multi_part = false; for arg in args { - let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(&arg)); + let (arg_ty, _) = walk_ptrs_ty_depth(cx.typeck_results().expr_ty(arg)); if match_type(cx, arg_ty, &paths::LINT) { // If we found the lint arg, extract the lint name @@ -458,7 +671,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for LintResolver<'a, 'hir> { if let ExprKind::Path(qpath) = &expr.kind; if let QPath::Resolved(_, path) = qpath; - let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr)); + let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr)); if match_type(self.cx, expr_ty, &paths::LINT); then { if let hir::def::Res::Def(DefKind::Static, _) = path.res { @@ -517,7 +730,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for ApplicabilityResolver<'a, 'hir> { } fn visit_expr(&mut self, expr: &'hir hir::Expr<'hir>) { - let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(&expr)); + let (expr_ty, _) = walk_ptrs_ty_depth(self.cx.typeck_results().expr_ty(expr)); if_chain! { if match_type(self.cx, expr_ty, &paths::APPLICABILITY); @@ -605,7 +818,7 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for IsMultiSpanScanner<'a, 'hir> { .any(|func_path| match_function_call(self.cx, fn_expr, func_path).is_some()); if found_function { // These functions are all multi part suggestions - self.add_single_span_suggestion() + self.add_single_span_suggestion(); } }, ExprKind::MethodCall(path, _path_span, arg, _arg_span) => { diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index febd4b6ff7b..1d5b7c98d31 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -1,5 +1,5 @@ -use crate::consts::{constant, Constant}; use crate::rustc_target::abi::LayoutOf; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; 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 ec209b30951..3ab68df2b6d 100644 --- a/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs +++ b/src/tools/clippy/clippy_lints/src/verbose_file_reads.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for VerboseFileReads { "use of `File::read_to_string`", None, "consider using `fs::read_to_string` instead", - ) + ); } } } diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 7e962472c07..5229a705865 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -279,8 +279,15 @@ impl EarlyLintPass for Write { span_lint(cx, PRINT_STDERR, mac.span(), "use of `eprintln!`"); self.lint_println_empty_string(cx, mac); } else if mac.path == sym!(write) { - if let (Some(fmt_str), _) = self.check_tts(cx, mac.args.inner_tokens(), true) { + if let (Some(fmt_str), dest) = self.check_tts(cx, mac.args.inner_tokens(), true) { if check_newlines(&fmt_str) { + let (nl_span, only_nl) = newline_span(&fmt_str); + let nl_span = match (dest, only_nl) { + // Special case of `write!(buf, "\n")`: Mark everything from the end of + // `buf` for removal so no trailing comma [`writeln!(buf, )`] remains. + (Some(dest_expr), true) => Span::new(dest_expr.span.hi(), nl_span.hi(), nl_span.ctxt()), + _ => nl_span, + }; span_lint_and_then( cx, WRITE_WITH_NEWLINE, @@ -289,14 +296,11 @@ impl EarlyLintPass for Write { |err| { err.multipart_suggestion( "use `writeln!()` instead", - vec![ - (mac.path.span, String::from("writeln")), - (newline_span(&fmt_str), String::new()), - ], + vec![(mac.path.span, String::from("writeln")), (nl_span, String::new())], Applicability::MachineApplicable, ); }, - ) + ); } } } else if mac.path == sym!(writeln) { @@ -329,12 +333,13 @@ impl EarlyLintPass for Write { /// Given a format string that ends in a newline and its span, calculates the span of the /// newline, or the format string itself if the format string consists solely of a newline. -fn newline_span(fmtstr: &StrLit) -> Span { +/// Return this and a boolean indicating whether it only consisted of a newline. +fn newline_span(fmtstr: &StrLit) -> (Span, bool) { let sp = fmtstr.span; let contents = &fmtstr.symbol.as_str(); if *contents == r"\n" { - return sp; + return (sp, true); } let newline_sp_hi = sp.hi() @@ -351,7 +356,7 @@ fn newline_span(fmtstr: &StrLit) -> Span { panic!("expected format string to contain a newline"); }; - sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi) + (sp.with_lo(newline_sp_hi - newline_sp_len).with_hi(newline_sp_hi), false) } /// Stores a list of replacement spans for each argument, but only if all the replacements used an @@ -613,7 +618,7 @@ impl Write { |err| { err.multipart_suggestion( &format!("use `{}!` instead", suggested), - vec![(mac.path.span, suggested), (newline_span(&fmt_str), String::new())], + vec![(mac.path.span, suggested), (newline_span(&fmt_str).0, String::new())], Applicability::MachineApplicable, ); }, diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs index 350b1cf25ff..a1ea743ba80 100644 --- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs +++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs @@ -1,4 +1,4 @@ -use crate::consts::{constant_simple, Constant}; +use clippy_utils::consts::{constant_simple, Constant}; use clippy_utils::diagnostics::span_lint_and_help; use if_chain::if_chain; use rustc_hir::{BinOpKind, Expr, ExprKind}; diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index 0a1d4e11142..93ed3b18400 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -14,6 +14,7 @@ unicode-normalization = "0.1" rustc-semver="1.1.0" [features] +deny-warnings = [] internal-lints = [] metadata-collector-lint = [] diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index c0584e1e226..0318c483959 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -115,7 +115,7 @@ fn parse_attrs<F: FnMut(u64)>(sess: &Session, attrs: &[ast::Attribute], name: &' for attr in get_attr(sess, attrs, name) { if let Some(ref value) = attr.value_str() { if let Ok(value) = FromStr::from_str(&value.as_str()) { - f(value) + f(value); } else { sess.span_err(attr.span, "not a number"); } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 2a305d8bcbe..0d7fdeeb920 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -229,25 +229,25 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> { match e.kind { ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)), - ExprKind::Block(ref block, _) => self.block(block), + ExprKind::Block(block, _) => self.block(block), ExprKind::Lit(ref lit) => Some(lit_to_constant(&lit.node, self.typeck_results.expr_ty_opt(e))), - ExprKind::Array(ref vec) => self.multi(vec).map(Constant::Vec), - ExprKind::Tup(ref tup) => self.multi(tup).map(Constant::Tuple), - ExprKind::Repeat(ref value, _) => { + ExprKind::Array(vec) => self.multi(vec).map(Constant::Vec), + ExprKind::Tup(tup) => self.multi(tup).map(Constant::Tuple), + ExprKind::Repeat(value, _) => { let n = match self.typeck_results.expr_ty(e).kind() { ty::Array(_, n) => n.try_eval_usize(self.lcx.tcx, self.lcx.param_env)?, _ => span_bug!(e.span, "typeck error"), }; self.expr(value).map(|v| Constant::Repeat(Box::new(v), n)) }, - ExprKind::Unary(op, ref operand) => self.expr(operand).and_then(|o| match op { + ExprKind::Unary(op, operand) => self.expr(operand).and_then(|o| match op { UnOp::Not => self.constant_not(&o, self.typeck_results.expr_ty(e)), UnOp::Neg => self.constant_negate(&o, self.typeck_results.expr_ty(e)), UnOp::Deref => Some(if let Constant::Ref(r) = o { *r } else { o }), }), - ExprKind::If(ref cond, ref then, ref otherwise) => self.ifthenelse(cond, then, *otherwise), - ExprKind::Binary(op, ref left, ref right) => self.binop(op, left, right), - ExprKind::Call(ref callee, ref args) => { + ExprKind::If(cond, then, ref otherwise) => self.ifthenelse(cond, then, *otherwise), + ExprKind::Binary(op, left, right) => self.binop(op, left, right), + ExprKind::Call(callee, args) => { // We only handle a few const functions for now. if_chain! { if args.is_empty(); @@ -273,8 +273,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { } } }, - ExprKind::Index(ref arr, ref index) => self.index(arr, index), - ExprKind::AddrOf(_, _, ref inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))), + ExprKind::Index(arr, index) => self.index(arr, index), + ExprKind::AddrOf(_, _, inner) => self.expr(inner).map(|r| Constant::Ref(Box::new(r))), // TODO: add other expressions. _ => None, } @@ -349,7 +349,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { ) .ok() .map(|val| rustc_middle::ty::Const::from_value(self.lcx.tcx, val, ty))?; - let result = miri_to_const(&result); + let result = miri_to_const(result); if result.is_some() { self.needed_resolution = true; } diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs index a4efae54894..7c94474cb35 100644 --- a/src/tools/clippy/clippy_utils/src/diagnostics.rs +++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs @@ -167,7 +167,7 @@ pub fn span_lint_hir_and_then( cx: &LateContext<'_>, lint: &'static Lint, hir_id: HirId, - sp: Span, + sp: impl Into<MultiSpan>, msg: &str, f: impl FnOnce(&mut DiagnosticBuilder<'_>), ) { @@ -223,7 +223,7 @@ pub fn multispan_sugg<I>(diag: &mut DiagnosticBuilder<'_>, help_msg: &str, sugg: where I: IntoIterator<Item = (Span, String)>, { - multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg) + multispan_sugg_with_applicability(diag, help_msg, Applicability::Unspecified, sugg); } /// Create a suggestion made from several `span → replacement`. diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 0c0e4d3b4ce..8be36756b33 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -58,7 +58,7 @@ pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> { } match expr.kind { - hir::ExprKind::Call(ref path, ref args) + hir::ExprKind::Call(path, args) if matches!( path.kind, hir::ExprKind::Path(hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, _)) @@ -70,7 +70,7 @@ pub fn range<'a>(expr: &'a hir::Expr<'_>) -> Option<Range<'a>> { limits: ast::RangeLimits::Closed, }) }, - hir::ExprKind::Struct(ref path, ref fields, None) => match path { + hir::ExprKind::Struct(path, fields, None) => match path { hir::QPath::LangItem(hir::LangItem::RangeFull, _) => Some(Range { start: None, end: None, @@ -112,7 +112,7 @@ pub fn is_from_for_desugar(local: &hir::Local<'_>) -> bool { // } // ``` if_chain! { - if let Some(ref expr) = local.init; + if let Some(expr) = local.init; if let hir::ExprKind::Match(_, _, hir::MatchSource::ForLoopDesugar) = expr.kind; then { return true; @@ -140,14 +140,14 @@ pub fn for_loop<'tcx>( expr: &'tcx hir::Expr<'tcx>, ) -> Option<(&hir::Pat<'_>, &'tcx hir::Expr<'tcx>, &'tcx hir::Expr<'tcx>, Span)> { if_chain! { - if let hir::ExprKind::Match(ref iterexpr, ref arms, hir::MatchSource::ForLoopDesugar) = expr.kind; - if let hir::ExprKind::Call(_, ref iterargs) = iterexpr.kind; + if let hir::ExprKind::Match(iterexpr, arms, hir::MatchSource::ForLoopDesugar) = expr.kind; + if let hir::ExprKind::Call(_, iterargs) = iterexpr.kind; if iterargs.len() == 1 && arms.len() == 1 && arms[0].guard.is_none(); - if let hir::ExprKind::Loop(ref block, ..) = arms[0].body.kind; + if let hir::ExprKind::Loop(block, ..) = arms[0].body.kind; if block.expr.is_none(); if let [ _, _, ref let_stmt, ref body ] = *block.stmts; - if let hir::StmtKind::Local(ref local) = let_stmt.kind; - if let hir::StmtKind::Expr(ref expr) = body.kind; + if let hir::StmtKind::Local(local) = let_stmt.kind; + if let hir::StmtKind::Expr(expr) = body.kind; then { return Some((&*local.pat, &iterargs[0], expr, arms[0].span)); } @@ -182,7 +182,7 @@ pub enum VecArgs<'a> { /// from `vec!`. pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<VecArgs<'e>> { if_chain! { - if let hir::ExprKind::Call(ref fun, ref args) = expr.kind; + if let hir::ExprKind::Call(fun, args) = expr.kind; if let hir::ExprKind::Path(ref qpath) = fun.kind; if is_expn_of(fun.span, "vec").is_some(); if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); @@ -194,8 +194,8 @@ pub fn vec_macro<'e>(cx: &LateContext<'_>, expr: &'e hir::Expr<'_>) -> Option<Ve else if match_def_path(cx, fun_def_id, &paths::SLICE_INTO_VEC) && args.len() == 1 { // `vec![a, b, c]` case if_chain! { - if let hir::ExprKind::Box(ref boxed) = args[0].kind; - if let hir::ExprKind::Array(ref args) = boxed.kind; + if let hir::ExprKind::Box(boxed) = args[0].kind; + if let hir::ExprKind::Array(args) = boxed.kind; then { return Some(VecArgs::Vec(&*args)); } @@ -227,7 +227,7 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx /// compared fn ast_matchblock(matchblock_expr: &'tcx Expr<'tcx>) -> Option<Vec<&Expr<'_>>> { if_chain! { - if let ExprKind::Match(ref headerexpr, _, _) = &matchblock_expr.kind; + if let ExprKind::Match(headerexpr, _, _) = &matchblock_expr.kind; if let ExprKind::Tup([lhs, rhs]) = &headerexpr.kind; if let ExprKind::AddrOf(BorrowKind::Ref, _, lhs) = lhs.kind; if let ExprKind::AddrOf(BorrowKind::Ref, _, rhs) = rhs.kind; @@ -238,12 +238,12 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx None } - if let ExprKind::Block(ref block, _) = e.kind { + if let ExprKind::Block(block, _) = e.kind { if block.stmts.len() == 1 { - if let StmtKind::Semi(ref matchexpr) = block.stmts.get(0)?.kind { + if let StmtKind::Semi(matchexpr) = block.stmts.get(0)?.kind { // macros with unique arg: `{debug_}assert!` (e.g., `debug_assert!(some_condition)`) if_chain! { - if let ExprKind::If(ref clause, _, _) = matchexpr.kind; + if let ExprKind::If(clause, _, _) = matchexpr.kind; if let ExprKind::Unary(UnOp::Not, condition) = clause.kind; then { return Some(vec![condition]); @@ -252,8 +252,8 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx // debug macros with two args: `debug_assert_{ne, eq}` (e.g., `assert_ne!(a, b)`) if_chain! { - if let ExprKind::Block(ref matchblock,_) = matchexpr.kind; - if let Some(ref matchblock_expr) = matchblock.expr; + if let ExprKind::Block(matchblock,_) = matchexpr.kind; + if let Some(matchblock_expr) = matchblock.expr; then { return ast_matchblock(matchblock_expr); } @@ -261,7 +261,7 @@ pub fn extract_assert_macro_args<'tcx>(e: &'tcx Expr<'tcx>) -> Option<Vec<&'tcx } } else if let Some(matchblock_expr) = block.expr { // macros with two args: `assert_{ne, eq}` (e.g., `assert_ne!(a, b)`) - return ast_matchblock(&matchblock_expr); + return ast_matchblock(matchblock_expr); } } None diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 3b01158acd9..a21ad42c061 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -2,20 +2,19 @@ use crate::consts::{constant_context, constant_simple}; use crate::differing_macro_contexts; use crate::source::snippet_opt; use rustc_ast::ast::InlineAsmTemplatePiece; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_data_structures::fx::FxHasher; use rustc_hir::def::Res; use rustc_hir::HirIdMap; use rustc_hir::{ - BinOpKind, Block, BlockCheckMode, BodyId, BorrowKind, CaptureBy, Expr, ExprField, ExprKind, FnRetTy, GenericArg, - GenericArgs, Guard, HirId, InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, - PathSegment, QPath, Stmt, StmtKind, Ty, TyKind, TypeBinding, + BinOpKind, Block, BodyId, Expr, ExprField, ExprKind, FnRetTy, GenericArg, GenericArgs, Guard, HirId, + InlineAsmOperand, Lifetime, LifetimeName, ParamName, Pat, PatField, PatKind, Path, PathSegment, QPath, Stmt, + StmtKind, Ty, TyKind, TypeBinding, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; -use rustc_middle::ich::StableHashingContextProvider; use rustc_middle::ty::TypeckResults; use rustc_span::Symbol; -use std::hash::Hash; +use std::hash::{Hash, Hasher}; /// Type used to check whether two ast are the same. This is different from the /// operator @@ -95,12 +94,12 @@ pub struct HirEqInterExpr<'a, 'b, 'tcx> { impl HirEqInterExpr<'_, '_, '_> { pub fn eq_stmt(&mut self, left: &Stmt<'_>, right: &Stmt<'_>) -> bool { match (&left.kind, &right.kind) { - (&StmtKind::Local(ref l), &StmtKind::Local(ref r)) => { + (&StmtKind::Local(l), &StmtKind::Local(r)) => { // This additional check ensures that the type of the locals are equivalent even if the init // expression or type have some inferred parts. if let Some(typeck) = self.inner.maybe_typeck_results { - let l_ty = typeck.pat_ty(&l.pat); - let r_ty = typeck.pat_ty(&r.pat); + let l_ty = typeck.pat_ty(l.pat); + let r_ty = typeck.pat_ty(r.pat); if !rustc_middle::ty::TyS::same_type(l_ty, r_ty) { return false; } @@ -110,11 +109,9 @@ impl HirEqInterExpr<'_, '_, '_> { // these only get added if the init and type is equal. both(&l.init, &r.init, |l, r| self.eq_expr(l, r)) && both(&l.ty, &r.ty, |l, r| self.eq_ty(l, r)) - && self.eq_pat(&l.pat, &r.pat) - }, - (&StmtKind::Expr(ref l), &StmtKind::Expr(ref r)) | (&StmtKind::Semi(ref l), &StmtKind::Semi(ref r)) => { - self.eq_expr(l, r) + && self.eq_pat(l.pat, r.pat) }, + (&StmtKind::Expr(l), &StmtKind::Expr(r)) | (&StmtKind::Semi(l), &StmtKind::Semi(r)) => self.eq_expr(l, r), _ => false, } } @@ -165,12 +162,18 @@ impl HirEqInterExpr<'_, '_, '_> { left.eq(right) }, _ => { - over(&left.stmts, &right.stmts, |l, r| self.eq_stmt(l, r)) + over(left.stmts, right.stmts, |l, r| self.eq_stmt(l, r)) && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) }, } } + pub fn eq_body(&mut self, left: BodyId, right: BodyId) -> bool { + let cx = self.inner.cx; + let eval_const = |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value); + eval_const(left) == eval_const(right) + } + #[allow(clippy::similar_names)] pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool { if !self.inner.allow_side_effects && differing_macro_contexts(left.span, right.span) { @@ -192,20 +195,20 @@ impl HirEqInterExpr<'_, '_, '_> { &reduce_exprkind(self.inner.cx, &left.kind), &reduce_exprkind(self.inner.cx, &right.kind), ) { - (&ExprKind::AddrOf(lb, l_mut, ref le), &ExprKind::AddrOf(rb, r_mut, ref re)) => { + (&ExprKind::AddrOf(lb, l_mut, le), &ExprKind::AddrOf(rb, r_mut, re)) => { lb == rb && l_mut == r_mut && self.eq_expr(le, re) }, (&ExprKind::Continue(li), &ExprKind::Continue(ri)) => { both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name) }, - (&ExprKind::Assign(ref ll, ref lr, _), &ExprKind::Assign(ref rl, ref rr, _)) => { + (&ExprKind::Assign(ll, lr, _), &ExprKind::Assign(rl, rr, _)) => { self.inner.allow_side_effects && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }, - (&ExprKind::AssignOp(ref lo, ref ll, ref lr), &ExprKind::AssignOp(ref ro, ref rl, ref rr)) => { + (&ExprKind::AssignOp(ref lo, ll, lr), &ExprKind::AssignOp(ref ro, rl, rr)) => { self.inner.allow_side_effects && lo.node == ro.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) }, - (&ExprKind::Block(ref l, _), &ExprKind::Block(ref r, _)) => self.eq_block(l, r), - (&ExprKind::Binary(l_op, ref ll, ref lr), &ExprKind::Binary(r_op, ref rl, ref rr)) => { + (&ExprKind::Block(l, _), &ExprKind::Block(r, _)) => self.eq_block(l, r), + (&ExprKind::Binary(l_op, ll, lr), &ExprKind::Binary(r_op, rl, rr)) => { l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) || swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| { l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr) @@ -215,58 +218,50 @@ impl HirEqInterExpr<'_, '_, '_> { both(&li.label, &ri.label, |l, r| l.ident.name == r.ident.name) && both(le, re, |l, r| self.eq_expr(l, r)) }, - (&ExprKind::Box(ref l), &ExprKind::Box(ref r)) => self.eq_expr(l, r), + (&ExprKind::Box(l), &ExprKind::Box(r)) => self.eq_expr(l, r), (&ExprKind::Call(l_fun, l_args), &ExprKind::Call(r_fun, r_args)) => { self.inner.allow_side_effects && self.eq_expr(l_fun, r_fun) && self.eq_exprs(l_args, r_args) }, - (&ExprKind::Cast(ref lx, ref lt), &ExprKind::Cast(ref rx, ref rt)) - | (&ExprKind::Type(ref lx, ref lt), &ExprKind::Type(ref rx, ref rt)) => { + (&ExprKind::Cast(lx, lt), &ExprKind::Cast(rx, rt)) | (&ExprKind::Type(lx, lt), &ExprKind::Type(rx, rt)) => { self.eq_expr(lx, rx) && self.eq_ty(lt, rt) }, - (&ExprKind::Field(ref l_f_exp, ref l_f_ident), &ExprKind::Field(ref r_f_exp, ref r_f_ident)) => { + (&ExprKind::Field(l_f_exp, ref l_f_ident), &ExprKind::Field(r_f_exp, ref r_f_ident)) => { l_f_ident.name == r_f_ident.name && self.eq_expr(l_f_exp, r_f_exp) }, - (&ExprKind::Index(ref la, ref li), &ExprKind::Index(ref ra, ref ri)) => { - self.eq_expr(la, ra) && self.eq_expr(li, ri) - }, - (&ExprKind::If(ref lc, ref lt, ref le), &ExprKind::If(ref rc, ref rt, ref re)) => { + (&ExprKind::Index(la, li), &ExprKind::Index(ra, ri)) => self.eq_expr(la, ra) && self.eq_expr(li, ri), + (&ExprKind::If(lc, lt, ref le), &ExprKind::If(rc, rt, ref re)) => { self.eq_expr(lc, rc) && self.eq_expr(&**lt, &**rt) && both(le, re, |l, r| self.eq_expr(l, r)) }, (&ExprKind::Lit(ref l), &ExprKind::Lit(ref r)) => l.node == r.node, - (&ExprKind::Loop(ref lb, ref ll, ref lls, _), &ExprKind::Loop(ref rb, ref rl, ref rls, _)) => { + (&ExprKind::Loop(lb, ref ll, ref lls, _), &ExprKind::Loop(rb, ref rl, ref rls, _)) => { lls == rls && self.eq_block(lb, rb) && both(ll, rl, |l, r| l.ident.name == r.ident.name) }, - (&ExprKind::Match(ref le, ref la, ref ls), &ExprKind::Match(ref re, ref ra, ref rs)) => { + (&ExprKind::Match(le, la, ref ls), &ExprKind::Match(re, ra, ref rs)) => { ls == rs && self.eq_expr(le, re) && over(la, ra, |l, r| { - self.eq_pat(&l.pat, &r.pat) + self.eq_pat(l.pat, r.pat) && both(&l.guard, &r.guard, |l, r| self.eq_guard(l, r)) - && self.eq_expr(&l.body, &r.body) + && self.eq_expr(l.body, r.body) }) }, (&ExprKind::MethodCall(l_path, _, l_args, _), &ExprKind::MethodCall(r_path, _, r_args, _)) => { self.inner.allow_side_effects && self.eq_path_segment(l_path, r_path) && self.eq_exprs(l_args, r_args) }, - (&ExprKind::Repeat(ref le, ref ll_id), &ExprKind::Repeat(ref re, ref rl_id)) => { - let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(ll_id.body)); - let ll = celcx.expr(&self.inner.cx.tcx.hir().body(ll_id.body).value); - let mut celcx = constant_context(self.inner.cx, self.inner.cx.tcx.typeck_body(rl_id.body)); - let rl = celcx.expr(&self.inner.cx.tcx.hir().body(rl_id.body).value); - - self.eq_expr(le, re) && ll == rl + (&ExprKind::Repeat(le, ref ll_id), &ExprKind::Repeat(re, ref rl_id)) => { + self.eq_expr(le, re) && self.eq_body(ll_id.body, rl_id.body) }, (&ExprKind::Ret(ref l), &ExprKind::Ret(ref r)) => both(l, r, |l, r| self.eq_expr(l, r)), (&ExprKind::Path(ref l), &ExprKind::Path(ref r)) => self.eq_qpath(l, r), - (&ExprKind::Struct(ref l_path, ref lf, ref lo), &ExprKind::Struct(ref r_path, ref rf, ref ro)) => { + (&ExprKind::Struct(l_path, lf, ref lo), &ExprKind::Struct(r_path, rf, ref ro)) => { self.eq_qpath(l_path, r_path) && both(lo, ro, |l, r| self.eq_expr(l, r)) && over(lf, rf, |l, r| self.eq_expr_field(l, r)) }, (&ExprKind::Tup(l_tup), &ExprKind::Tup(r_tup)) => self.eq_exprs(l_tup, r_tup), - (&ExprKind::Unary(l_op, ref le), &ExprKind::Unary(r_op, ref re)) => l_op == r_op && self.eq_expr(le, re), + (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re), (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r), - (&ExprKind::DropTemps(ref le), &ExprKind::DropTemps(ref re)) => self.eq_expr(le, re), + (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re), _ => false, }; is_eq || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right)) @@ -277,7 +272,7 @@ impl HirEqInterExpr<'_, '_, '_> { } fn eq_expr_field(&mut self, left: &ExprField<'_>, right: &ExprField<'_>) -> bool { - left.ident.name == right.ident.name && self.eq_expr(&left.expr, &right.expr) + left.ident.name == right.ident.name && self.eq_expr(left.expr, right.expr) } fn eq_guard(&mut self, left: &Guard<'_>, right: &Guard<'_>) -> bool { @@ -290,6 +285,7 @@ impl HirEqInterExpr<'_, '_, '_> { fn eq_generic_arg(&mut self, left: &GenericArg<'_>, right: &GenericArg<'_>) -> bool { match (left, right) { + (GenericArg::Const(l), GenericArg::Const(r)) => self.eq_body(l.value.body, r.value.body), (GenericArg::Lifetime(l_lt), GenericArg::Lifetime(r_lt)) => Self::eq_lifetime(l_lt, r_lt), (GenericArg::Type(l_ty), GenericArg::Type(r_ty)) => self.eq_ty(l_ty, r_ty), _ => false, @@ -308,11 +304,11 @@ impl HirEqInterExpr<'_, '_, '_> { /// Checks whether two patterns are the same. fn eq_pat(&mut self, left: &Pat<'_>, right: &Pat<'_>) -> bool { match (&left.kind, &right.kind) { - (&PatKind::Box(ref l), &PatKind::Box(ref r)) => self.eq_pat(l, r), - (&PatKind::Struct(ref lp, ref la, ..), &PatKind::Struct(ref rp, ref ra, ..)) => { + (&PatKind::Box(l), &PatKind::Box(r)) => self.eq_pat(l, r), + (&PatKind::Struct(ref lp, la, ..), &PatKind::Struct(ref rp, ra, ..)) => { self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat_field(l, r)) }, - (&PatKind::TupleStruct(ref lp, ref la, ls), &PatKind::TupleStruct(ref rp, ref ra, rs)) => { + (&PatKind::TupleStruct(ref lp, la, ls), &PatKind::TupleStruct(ref rp, ra, rs)) => { self.eq_qpath(lp, rp) && over(la, ra, |l, r| self.eq_pat(l, r)) && ls == rs }, (&PatKind::Binding(lb, li, _, ref lp), &PatKind::Binding(rb, ri, _, ref rp)) => { @@ -323,15 +319,13 @@ impl HirEqInterExpr<'_, '_, '_> { eq }, (&PatKind::Path(ref l), &PatKind::Path(ref r)) => self.eq_qpath(l, r), - (&PatKind::Lit(ref l), &PatKind::Lit(ref r)) => self.eq_expr(l, r), - (&PatKind::Tuple(ref l, ls), &PatKind::Tuple(ref r, rs)) => { - ls == rs && over(l, r, |l, r| self.eq_pat(l, r)) - }, + (&PatKind::Lit(l), &PatKind::Lit(r)) => self.eq_expr(l, r), + (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)), (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => { both(ls, rs, |a, b| self.eq_expr(a, b)) && both(le, re, |a, b| self.eq_expr(a, b)) && (li == ri) }, - (&PatKind::Ref(ref le, ref lm), &PatKind::Ref(ref re, ref rm)) => lm == rm && self.eq_pat(le, re), - (&PatKind::Slice(ref ls, ref li, ref le), &PatKind::Slice(ref rs, ref ri, ref re)) => { + (&PatKind::Ref(le, ref lm), &PatKind::Ref(re, ref rm)) => lm == rm && self.eq_pat(le, re), + (&PatKind::Slice(ls, ref li, le), &PatKind::Slice(rs, ref ri, re)) => { over(ls, rs, |l, r| self.eq_pat(l, r)) && over(le, re, |l, r| self.eq_pat(l, r)) && both(li, ri, |l, r| self.eq_pat(l, r)) @@ -344,10 +338,10 @@ impl HirEqInterExpr<'_, '_, '_> { #[allow(clippy::similar_names)] fn eq_qpath(&mut self, left: &QPath<'_>, right: &QPath<'_>) -> bool { match (left, right) { - (&QPath::Resolved(ref lty, ref lpath), &QPath::Resolved(ref rty, ref rpath)) => { + (&QPath::Resolved(ref lty, lpath), &QPath::Resolved(ref rty, rpath)) => { both(lty, rty, |l, r| self.eq_ty(l, r)) && self.eq_path(lpath, rpath) }, - (&QPath::TypeRelative(ref lty, ref lseg), &QPath::TypeRelative(ref rty, ref rseg)) => { + (&QPath::TypeRelative(lty, lseg), &QPath::TypeRelative(rty, rseg)) => { self.eq_ty(lty, rty) && self.eq_path_segment(lseg, rseg) }, (&QPath::LangItem(llang_item, _), &QPath::LangItem(rlang_item, _)) => llang_item == rlang_item, @@ -359,14 +353,14 @@ impl HirEqInterExpr<'_, '_, '_> { match (left.res, right.res) { (Res::Local(l), Res::Local(r)) => l == r || self.locals.get(&l) == Some(&r), (Res::Local(_), _) | (_, Res::Local(_)) => false, - _ => over(&left.segments, &right.segments, |l, r| self.eq_path_segment(l, r)), + _ => over(left.segments, right.segments, |l, r| self.eq_path_segment(l, r)), } } fn eq_path_parameters(&mut self, left: &GenericArgs<'_>, right: &GenericArgs<'_>) -> bool { if !(left.parenthesized || right.parenthesized) { - over(&left.args, &right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work - && over(&left.bindings, &right.bindings, |l, r| self.eq_type_binding(l, r)) + over(left.args, right.args, |l, r| self.eq_generic_arg(l, r)) // FIXME(flip1995): may not work + && over(left.bindings, right.bindings, |l, r| self.eq_type_binding(l, r)) } else if left.parenthesized && right.parenthesized { over(left.inputs(), right.inputs(), |l, r| self.eq_ty(l, r)) && both(&Some(&left.bindings[0].ty()), &Some(&right.bindings[0].ty()), |l, r| { @@ -390,12 +384,9 @@ impl HirEqInterExpr<'_, '_, '_> { #[allow(clippy::similar_names)] fn eq_ty(&mut self, left: &Ty<'_>, right: &Ty<'_>) -> bool { match (&left.kind, &right.kind) { - (&TyKind::Slice(ref l_vec), &TyKind::Slice(ref r_vec)) => self.eq_ty(l_vec, r_vec), - (&TyKind::Array(ref lt, ref ll_id), &TyKind::Array(ref rt, ref rl_id)) => { - let cx = self.inner.cx; - let eval_const = - |body| constant_context(cx, cx.tcx.typeck_body(body)).expr(&cx.tcx.hir().body(body).value); - self.eq_ty(lt, rt) && eval_const(ll_id.body) == eval_const(rl_id.body) + (&TyKind::Slice(l_vec), &TyKind::Slice(r_vec)) => self.eq_ty(l_vec, r_vec), + (&TyKind::Array(lt, ref ll_id), &TyKind::Array(rt, ref rl_id)) => { + self.eq_ty(lt, rt) && self.eq_body(ll_id.body, rl_id.body) }, (&TyKind::Ptr(ref l_mut), &TyKind::Ptr(ref r_mut)) => { l_mut.mutbl == r_mut.mutbl && self.eq_ty(&*l_mut.ty, &*r_mut.ty) @@ -404,14 +395,14 @@ impl HirEqInterExpr<'_, '_, '_> { l_rmut.mutbl == r_rmut.mutbl && self.eq_ty(&*l_rmut.ty, &*r_rmut.ty) }, (&TyKind::Path(ref l), &TyKind::Path(ref r)) => self.eq_qpath(l, r), - (&TyKind::Tup(ref l), &TyKind::Tup(ref r)) => over(l, r, |l, r| self.eq_ty(l, r)), + (&TyKind::Tup(l), &TyKind::Tup(r)) => over(l, r, |l, r| self.eq_ty(l, r)), (&TyKind::Infer, &TyKind::Infer) => true, _ => false, } } fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool { - left.ident.name == right.ident.name && self.eq_ty(&left.ty(), &right.ty()) + left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty()) } } @@ -519,7 +510,7 @@ pub struct SpanlessHash<'a, 'tcx> { /// Context used to evaluate constant expressions. cx: &'a LateContext<'tcx>, maybe_typeck_results: Option<&'tcx TypeckResults<'tcx>>, - s: StableHasher, + s: FxHasher, } impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { @@ -527,7 +518,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { Self { cx, maybe_typeck_results: cx.maybe_typeck_results(), - s: StableHasher::new(), + s: FxHasher::default(), } } @@ -540,17 +531,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_stmt(s); } - if let Some(ref e) = b.expr { + if let Some(e) = b.expr { self.hash_expr(e); } - match b.rules { - BlockCheckMode::DefaultBlock => 0, - BlockCheckMode::UnsafeBlock(_) => 1, - BlockCheckMode::PushUnsafeBlock(_) => 2, - BlockCheckMode::PopUnsafeBlock(_) => 3, - } - .hash(&mut self.s); + std::mem::discriminant(&b.rules).hash(&mut self.s); } #[allow(clippy::many_single_char_names, clippy::too_many_lines)] @@ -561,21 +546,16 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { // const hashing may result in the same hash as some unrelated node, so add a sort of // discriminant depending on which path we're choosing next - simple_const.is_some().hash(&mut self.s); - - if let Some(e) = simple_const { - return e.hash(&mut self.s); + simple_const.hash(&mut self.s); + if simple_const.is_some() { + return; } std::mem::discriminant(&e.kind).hash(&mut self.s); match e.kind { - ExprKind::AddrOf(kind, m, ref e) => { - match kind { - BorrowKind::Ref => 0, - BorrowKind::Raw => 1, - } - .hash(&mut self.s); + ExprKind::AddrOf(kind, m, e) => { + std::mem::discriminant(&kind).hash(&mut self.s); m.hash(&mut self.s); self.hash_expr(e); }, @@ -584,22 +564,20 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_name(i.ident.name); } }, - ExprKind::Assign(ref l, ref r, _) => { + ExprKind::Assign(l, r, _) => { self.hash_expr(l); self.hash_expr(r); }, - ExprKind::AssignOp(ref o, ref l, ref r) => { - o.node - .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s); + ExprKind::AssignOp(ref o, l, r) => { + std::mem::discriminant(&o.node).hash(&mut self.s); self.hash_expr(l); self.hash_expr(r); }, - ExprKind::Block(ref b, _) => { + ExprKind::Block(b, _) => { self.hash_block(b); }, - ExprKind::Binary(op, ref l, ref r) => { - op.node - .hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s); + ExprKind::Binary(op, l, r) => { + std::mem::discriminant(&op.node).hash(&mut self.s); self.hash_expr(l); self.hash_expr(r); }, @@ -607,39 +585,35 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { if let Some(i) = i.label { self.hash_name(i.ident.name); } - if let Some(ref j) = *j { + if let Some(j) = *j { self.hash_expr(&*j); } }, - ExprKind::Box(ref e) | ExprKind::DropTemps(ref e) | ExprKind::Yield(ref e, _) => { + ExprKind::Box(e) | ExprKind::DropTemps(e) | ExprKind::Yield(e, _) => { self.hash_expr(e); }, - ExprKind::Call(ref fun, args) => { + ExprKind::Call(fun, args) => { self.hash_expr(fun); self.hash_exprs(args); }, - ExprKind::Cast(ref e, ref ty) | ExprKind::Type(ref e, ref ty) => { + ExprKind::Cast(e, ty) | ExprKind::Type(e, ty) => { self.hash_expr(e); self.hash_ty(ty); }, ExprKind::Closure(cap, _, eid, _, _) => { - match cap { - CaptureBy::Value => 0, - CaptureBy::Ref => 1, - } - .hash(&mut self.s); + std::mem::discriminant(&cap).hash(&mut self.s); // closures inherit TypeckResults self.hash_expr(&self.cx.tcx.hir().body(eid).value); }, - ExprKind::Field(ref e, ref f) => { + ExprKind::Field(e, ref f) => { self.hash_expr(e); self.hash_name(f.name); }, - ExprKind::Index(ref a, ref i) => { + ExprKind::Index(a, i) => { self.hash_expr(a); self.hash_expr(i); }, - ExprKind::InlineAsm(ref asm) => { + ExprKind::InlineAsm(asm) => { for piece in asm.template { match piece { InlineAsmTemplatePiece::String(s) => s.hash(&mut self.s), @@ -694,22 +668,20 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { ExprKind::Lit(ref l) => { l.node.hash(&mut self.s); }, - ExprKind::Loop(ref b, ref i, ..) => { + ExprKind::Loop(b, ref i, ..) => { self.hash_block(b); if let Some(i) = *i { self.hash_name(i.ident.name); } }, - ExprKind::If(ref cond, ref then, ref else_opt) => { - let c: fn(_, _, _) -> _ = ExprKind::If; - c.hash(&mut self.s); + ExprKind::If(cond, then, ref else_opt) => { self.hash_expr(cond); - self.hash_expr(&**then); - if let Some(ref e) = *else_opt { + self.hash_expr(then); + if let Some(e) = *else_opt { self.hash_expr(e); } }, - ExprKind::Match(ref e, arms, ref s) => { + ExprKind::Match(e, arms, ref s) => { self.hash_expr(e); for arm in arms { @@ -717,39 +689,39 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { if let Some(ref e) = arm.guard { self.hash_guard(e); } - self.hash_expr(&arm.body); + self.hash_expr(arm.body); } s.hash(&mut self.s); }, - ExprKind::MethodCall(ref path, ref _tys, args, ref _fn_span) => { + ExprKind::MethodCall(path, ref _tys, args, ref _fn_span) => { self.hash_name(path.ident.name); self.hash_exprs(args); }, ExprKind::ConstBlock(ref l_id) => { self.hash_body(l_id.body); }, - ExprKind::Repeat(ref e, ref l_id) => { + ExprKind::Repeat(e, ref l_id) => { self.hash_expr(e); self.hash_body(l_id.body); }, ExprKind::Ret(ref e) => { - if let Some(ref e) = *e { + if let Some(e) = *e { self.hash_expr(e); } }, ExprKind::Path(ref qpath) => { self.hash_qpath(qpath); }, - ExprKind::Struct(ref path, fields, ref expr) => { + ExprKind::Struct(path, fields, ref expr) => { self.hash_qpath(path); for f in fields { self.hash_name(f.ident.name); - self.hash_expr(&f.expr); + self.hash_expr(f.expr); } - if let Some(ref e) = *expr { + if let Some(e) = *expr { self.hash_expr(e); } }, @@ -759,8 +731,8 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { ExprKind::Array(v) => { self.hash_exprs(v); }, - ExprKind::Unary(lop, ref le) => { - lop.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s); + ExprKind::Unary(lop, le) => { + std::mem::discriminant(&lop).hash(&mut self.s); self.hash_expr(le); }, } @@ -773,19 +745,19 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } pub fn hash_name(&mut self, n: Symbol) { - n.as_str().hash(&mut self.s); + n.hash(&mut self.s); } pub fn hash_qpath(&mut self, p: &QPath<'_>) { match *p { - QPath::Resolved(_, ref path) => { + QPath::Resolved(_, path) => { self.hash_path(path); }, - QPath::TypeRelative(_, ref path) => { + QPath::TypeRelative(_, path) => { self.hash_name(path.ident.name); }, QPath::LangItem(lang_item, ..) => { - lang_item.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s); + std::mem::discriminant(&lang_item).hash(&mut self.s); }, } // self.maybe_typeck_results.unwrap().qpath_res(p, id).hash(&mut self.s); @@ -795,7 +767,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { std::mem::discriminant(&pat.kind).hash(&mut self.s); match pat.kind { PatKind::Binding(ann, _, _, pat) => { - ann.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s); + std::mem::discriminant(&ann).hash(&mut self.s); if let Some(pat) = pat { self.hash_pat(pat); } @@ -815,11 +787,11 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { if let Some(e) = e { self.hash_expr(e); } - i.hash_stable(&mut self.cx.tcx.get_stable_hashing_context(), &mut self.s); + std::mem::discriminant(&i).hash(&mut self.s); }, - PatKind::Ref(pat, m) => { + PatKind::Ref(pat, mu) => { self.hash_pat(pat); - m.hash(&mut self.s); + std::mem::discriminant(&mu).hash(&mut self.s); }, PatKind::Slice(l, m, r) => { for pat in l { @@ -838,7 +810,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_name(f.ident.name); self.hash_pat(f.pat); } - e.hash(&mut self.s) + e.hash(&mut self.s); }, PatKind::Tuple(pats, e) => { for pat in pats { @@ -864,6 +836,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { _ => { for seg in path.segments { self.hash_name(seg.ident.name); + self.hash_generic_args(seg.args().args); } }, } @@ -875,7 +848,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { match &b.kind { StmtKind::Local(local) => { self.hash_pat(local.pat); - if let Some(ref init) = local.init { + if let Some(init) = local.init { self.hash_expr(init); } }, @@ -888,7 +861,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { pub fn hash_guard(&mut self, g: &Guard<'_>) { match g { - Guard::If(ref expr) | Guard::IfLet(_, ref expr) => { + Guard::If(expr) | Guard::IfLet(_, expr) => { self.hash_expr(expr); }, } @@ -921,25 +894,24 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_body(anon_const.body); }, TyKind::Ptr(ref mut_ty) => { - self.hash_ty(&mut_ty.ty); + self.hash_ty(mut_ty.ty); mut_ty.mutbl.hash(&mut self.s); }, TyKind::Rptr(lifetime, ref mut_ty) => { self.hash_lifetime(lifetime); - self.hash_ty(&mut_ty.ty); + self.hash_ty(mut_ty.ty); mut_ty.mutbl.hash(&mut self.s); }, TyKind::BareFn(bfn) => { bfn.unsafety.hash(&mut self.s); bfn.abi.hash(&mut self.s); for arg in bfn.decl.inputs { - self.hash_ty(&arg); + self.hash_ty(arg); } + std::mem::discriminant(&bfn.decl.output).hash(&mut self.s); match bfn.decl.output { - FnRetTy::DefaultReturn(_) => { - ().hash(&mut self.s); - }, - FnRetTy::Return(ref ty) => { + FnRetTy::DefaultReturn(_) => {}, + FnRetTy::Return(ty) => { self.hash_ty(ty); }, } @@ -950,24 +922,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_ty(ty); } }, - TyKind::Path(ref qpath) => match qpath { - QPath::Resolved(ref maybe_ty, ref path) => { - if let Some(ref ty) = maybe_ty { - self.hash_ty(ty); - } - for segment in path.segments { - segment.ident.name.hash(&mut self.s); - self.hash_generic_args(segment.args().args); - } - }, - QPath::TypeRelative(ref ty, ref segment) => { - self.hash_ty(ty); - segment.ident.name.hash(&mut self.s); - }, - QPath::LangItem(lang_item, ..) => { - lang_item.hash(&mut self.s); - }, - }, + TyKind::Path(ref qpath) => self.hash_qpath(qpath), TyKind::OpaqueDef(_, arg_list) => { self.hash_generic_args(arg_list); }, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 9ac9500b4eb..769836aaf18 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,10 +1,16 @@ #![feature(box_patterns)] #![feature(in_band_lifetimes)] #![feature(iter_zip)] -#![cfg_attr(bootstrap, feature(or_patterns))] #![feature(rustc_private)] #![recursion_limit = "512"] +#![cfg_attr(feature = "deny-warnings", deny(warnings))] #![allow(clippy::missing_errors_doc, clippy::missing_panics_doc, clippy::must_use_candidate)] +// warn on the same lints as `clippy_lints` +#![warn(trivial_casts, trivial_numeric_casts)] +// warn on lints, that are included in `rust-lang/rust`s bootstrap +#![warn(rust_2018_idioms, unused_lifetimes)] +// warn on rustc internal lints +#![warn(rustc::internal)] // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) @@ -57,7 +63,7 @@ use std::hash::BuildHasherDefault; use if_chain::if_chain; use rustc_ast::ast::{self, Attribute, BorrowKind, LitKind}; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::unhash::UnhashMap; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; @@ -322,7 +328,7 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) /// Checks if an expression references a variable of the given name. pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool { - if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind { + if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind { if let [p] = path.segments { return p.ident.name == var; } @@ -332,8 +338,8 @@ pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool { pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> { match *path { - QPath::Resolved(_, ref path) => path.segments.last().expect("A path must have at least one segment"), - QPath::TypeRelative(_, ref seg) => seg, + QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"), + QPath::TypeRelative(_, seg) => seg, QPath::LangItem(..) => panic!("last_path_segment: lang item has no path segments"), } } @@ -361,8 +367,8 @@ pub fn get_qpath_generic_tys(path: &QPath<'tcx>) -> impl Iterator<Item = &'tcx h pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment<'tcx>> { match *path { - QPath::Resolved(_, ref path) => path.segments.get(0), - QPath::TypeRelative(_, ref seg) => Some(seg), + QPath::Resolved(_, path) => path.segments.get(0), + QPath::TypeRelative(_, seg) => Some(seg), QPath::LangItem(..) => None, } } @@ -382,8 +388,8 @@ pub fn single_segment_path<'tcx>(path: &QPath<'tcx>) -> Option<&'tcx PathSegment /// ``` pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool { match *path { - QPath::Resolved(_, ref path) => match_path(path, segments), - QPath::TypeRelative(ref ty, ref segment) => match ty.kind { + QPath::Resolved(_, path) => match_path(path, segments), + QPath::TypeRelative(ty, segment) => match ty.kind { TyKind::Path(ref inner_path) => { if let [prefix @ .., end] = segments { if match_qpath(inner_path, prefix) { @@ -451,7 +457,7 @@ pub fn match_path(path: &Path<'_>, segments: &[&str]) -> bool { /// If the expression is a path to a local, returns the canonical `HirId` of the local. pub fn path_to_local(expr: &Expr<'_>) -> Option<HirId> { - if let ExprKind::Path(QPath::Resolved(None, ref path)) = expr.kind { + if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind { if let Res::Local(id) = path.res { return Some(id); } @@ -655,13 +661,13 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec let mut matched = Vec::with_capacity(methods.len()); for method_name in methods.iter().rev() { // method chains are stored last -> first - if let ExprKind::MethodCall(ref path, _, ref args, _) = current.kind { + if let ExprKind::MethodCall(path, _, args, _) = current.kind { if path.ident.name.as_str() == *method_name { if args.iter().any(|e| e.span.from_expansion()) { return None; } - matched.push(&**args); // build up `matched` backwards - current = &args[0] // go to parent expression + matched.push(args); // build up `matched` backwards + current = &args[0]; // go to parent expression } else { return None; } @@ -706,7 +712,7 @@ pub fn get_pat_name(pat: &Pat<'_>) -> Option<Symbol> { match pat.kind { PatKind::Binding(.., ref spname, _) => Some(spname.name), PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name), - PatKind::Box(ref p) | PatKind::Ref(ref p, _) => get_pat_name(&*p), + PatKind::Box(p) | PatKind::Ref(p, _) => get_pat_name(&*p), _ => None, } } @@ -848,13 +854,31 @@ pub fn get_enclosing_block<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Optio kind: ImplItemKind::Fn(_, eid), .. }) => match cx.tcx.hir().body(eid).value.kind { - ExprKind::Block(ref block, _) => Some(block), + ExprKind::Block(block, _) => Some(block), _ => None, }, _ => None, }) } +/// Gets the loop enclosing the given expression, if any. +pub fn get_enclosing_loop(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<&'tcx Expr<'tcx>> { + let map = tcx.hir(); + for (_, node) in map.parent_iter(expr.hir_id) { + match node { + Node::Expr( + e @ Expr { + kind: ExprKind::Loop(..), + .. + }, + ) => return Some(e), + Node::Expr(_) | Node::Stmt(_) | Node::Block(_) | Node::Local(_) | Node::Arm(_) => (), + _ => break, + } + } + None +} + /// Gets the parent node if it's an impl block. pub fn get_parent_as_impl(tcx: TyCtxt<'_>, id: HirId) -> Option<&Impl<'_>> { let map = tcx.hir(); @@ -947,7 +971,12 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> { let data = span.ctxt().outer_expn_data(); let new_span = data.call_site; - if let ExpnKind::Macro { kind: MacroKind::Bang, name: mac_name, proc_macro: _ } = data.kind { + if let ExpnKind::Macro { + kind: MacroKind::Bang, + name: mac_name, + proc_macro: _, + } = data.kind + { if mac_name.as_str() == name { return Some(new_span); } @@ -975,7 +1004,12 @@ pub fn is_direct_expn_of(span: Span, name: &str) -> Option<Span> { let data = span.ctxt().outer_expn_data(); let new_span = data.call_site; - if let ExpnKind::Macro { kind: MacroKind::Bang, name: mac_name, proc_macro: _ } = data.kind { + if let ExpnKind::Macro { + kind: MacroKind::Bang, + name: mac_name, + proc_macro: _, + } = data.kind + { if mac_name.as_str() == name { return Some(new_span); } @@ -994,7 +1028,7 @@ pub fn return_ty<'tcx>(cx: &LateContext<'tcx>, fn_item: hir::HirId) -> Ty<'tcx> /// Checks if an expression is constructing a tuple-like enum variant or struct pub fn is_ctor_or_promotable_const_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { - if let ExprKind::Call(ref fun, _) = expr.kind { + if let ExprKind::Call(fun, _) = expr.kind { if let ExprKind::Path(ref qp) = fun.kind { let res = cx.qpath_res(qp, fun.hir_id); return match res { @@ -1024,21 +1058,21 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { match pat.kind { PatKind::Wild => false, PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)), - PatKind::Box(ref pat) | PatKind::Ref(ref pat, _) => is_refutable(cx, pat), + PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat), PatKind::Lit(..) | PatKind::Range(..) => true, PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id), - PatKind::Or(ref pats) => { + PatKind::Or(pats) => { // TODO: should be the honest check, that pats is exhaustive set are_refutable(cx, pats.iter().map(|pat| &**pat)) }, - PatKind::Tuple(ref pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)), - PatKind::Struct(ref qpath, ref fields, _) => { + PatKind::Tuple(pats, _) => are_refutable(cx, pats.iter().map(|pat| &**pat)), + PatKind::Struct(ref qpath, fields, _) => { is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, fields.iter().map(|field| &*field.pat)) }, - PatKind::TupleStruct(ref qpath, ref pats, _) => { + PatKind::TupleStruct(ref qpath, pats, _) => { is_enum_variant(cx, qpath, pat.hir_id) || are_refutable(cx, pats.iter().map(|pat| &**pat)) }, - PatKind::Slice(ref head, ref middle, ref tail) => { + PatKind::Slice(head, ref middle, tail) => { match &cx.typeck_results().node_type(pat.hir_id).kind() { rustc_ty::Slice(..) => { // [..] is the only irrefutable slice pattern. @@ -1060,9 +1094,9 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool { /// the function once on the given pattern. pub fn recurse_or_patterns<'tcx, F: FnMut(&'tcx Pat<'tcx>)>(pat: &'tcx Pat<'tcx>, mut f: F) { if let PatKind::Or(pats) = pat.kind { - pats.iter().copied().for_each(f) + pats.iter().copied().for_each(f); } else { - f(pat) + f(pat); } } @@ -1077,7 +1111,7 @@ pub fn is_automatically_derived(attrs: &[ast::Attribute]) -> bool { /// Ie. `x`, `{ x }` and `{{{{ x }}}}` all give `x`. `{ x; y }` and `{}` return /// themselves. pub fn remove_blocks<'tcx>(mut expr: &'tcx Expr<'tcx>) -> &'tcx Expr<'tcx> { - while let ExprKind::Block(ref block, ..) = expr.kind { + while let ExprKind::Block(block, ..) = expr.kind { match (block.stmts.is_empty(), block.expr.as_ref()) { (true, Some(e)) => expr = e, _ => break, @@ -1096,7 +1130,7 @@ pub fn is_self(slf: &Param<'_>) -> bool { pub fn is_self_ty(slf: &hir::Ty<'_>) -> bool { if_chain! { - if let TyKind::Path(QPath::Resolved(None, ref path)) = slf.kind; + if let TyKind::Path(QPath::Resolved(None, path)) = slf.kind; if let Res::SelfTy(..) = path.res; then { return true @@ -1114,7 +1148,7 @@ pub fn iter_input_pats<'tcx>(decl: &FnDecl<'_>, body: &'tcx Body<'_>) -> impl It pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tcx Expr<'tcx>> { fn is_ok(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool { if_chain! { - if let PatKind::TupleStruct(ref path, ref pat, None) = arm.pat.kind; + if let PatKind::TupleStruct(ref path, pat, None) = arm.pat.kind; if is_lang_ctor(cx, path, ResultOk); if let PatKind::Binding(_, hir_id, _, None) = pat[0].kind; if path_to_local_id(arm.body, hir_id); @@ -1133,7 +1167,7 @@ pub fn is_try<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<&'tc } } - if let ExprKind::Match(_, ref arms, ref source) = expr.kind { + if let ExprKind::Match(_, arms, ref source) = expr.kind { // desugared from a `?` operator if let MatchSource::TryDesugar = *source { return Some(expr); @@ -1220,12 +1254,12 @@ pub fn match_function_call<'tcx>( path: &[&str], ) -> Option<&'tcx [Expr<'tcx>]> { if_chain! { - if let ExprKind::Call(ref fun, ref args) = expr.kind; + if let ExprKind::Call(fun, args) = expr.kind; if let ExprKind::Path(ref qpath) = fun.kind; if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id(); if match_def_path(cx, fun_def_id, path); then { - return Some(&args) + return Some(args) } }; None @@ -1282,15 +1316,15 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, let mut conds = Vec::new(); let mut blocks: Vec<&Block<'_>> = Vec::new(); - while let ExprKind::If(ref cond, ref then_expr, ref else_expr) = expr.kind { - conds.push(&**cond); - if let ExprKind::Block(ref block, _) = then_expr.kind { + while let ExprKind::If(cond, then_expr, ref else_expr) = expr.kind { + conds.push(cond); + if let ExprKind::Block(block, _) = then_expr.kind { blocks.push(block); } else { panic!("ExprKind::If node is not an ExprKind::Block"); } - if let Some(ref else_expr) = *else_expr { + if let Some(else_expr) = *else_expr { expr = else_expr; } else { break; @@ -1299,8 +1333,8 @@ pub fn if_sequence<'tcx>(mut expr: &'tcx Expr<'tcx>) -> (Vec<&'tcx Expr<'tcx>>, // final `else {..}` if !blocks.is_empty() { - if let ExprKind::Block(ref block, _) = expr.kind { - blocks.push(&**block); + if let ExprKind::Block(block, _) = expr.kind { + blocks.push(block); } } @@ -1349,7 +1383,7 @@ pub fn must_use_attr(attrs: &[Attribute]) -> Option<&Attribute> { // check if expr is calling method or function with #[must_use] attribute pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { let did = match expr.kind { - ExprKind::Call(ref path, _) => if_chain! { + ExprKind::Call(path, _) => if_chain! { if let ExprKind::Path(ref qpath) = path.kind; if let def::Res::Def(_, did) = cx.qpath_res(qpath, path.hir_id); then { @@ -1362,7 +1396,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool { _ => None, }; - did.map_or(false, |did| must_use_attr(&cx.tcx.get_attrs(did)).is_some()) + did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some()) } /// Gets the node where an expression is either used, or it's type is unified with another branch. @@ -1538,14 +1572,16 @@ where Hash: Fn(&T) -> u64, Eq: Fn(&T, &T) -> bool, { - if exprs.len() == 2 && eq(&exprs[0], &exprs[1]) { - return vec![(&exprs[0], &exprs[1])]; + match exprs { + [a, b] if eq(a, b) => return vec![(a, b)], + _ if exprs.len() <= 2 => return vec![], + _ => {}, } let mut match_expr_list: Vec<(&T, &T)> = Vec::new(); - let mut map: FxHashMap<_, Vec<&_>> = - FxHashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default()); + let mut map: UnhashMap<u64, Vec<&_>> = + UnhashMap::with_capacity_and_hasher(exprs.len(), BuildHasherDefault::default()); for expr in exprs { match map.entry(hash(expr)) { diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_utils/src/msrvs.rs index 00df04c0144..4a9c4fd0276 100644 --- a/src/tools/clippy/clippy_utils/src/msrvs.rs +++ b/src/tools/clippy/clippy_utils/src/msrvs.rs @@ -26,4 +26,5 @@ msrv_aliases! { 1,34,0 { TRY_FROM } 1,30,0 { ITERATOR_FIND_MAP } 1,17,0 { FIELD_INIT_SHORTHAND, STATIC_IN_CONST } + 1,16,0 { STR_REPEAT } } diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs index 268bc5b3205..546706d51d7 100644 --- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs +++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs @@ -52,7 +52,7 @@ impl<'a> NumericLiteral<'a> { pub fn from_lit_kind(src: &'a str, lit_kind: &LitKind) -> Option<NumericLiteral<'a>> { if lit_kind.is_numeric() && src.chars().next().map_or(false, |c| c.is_digit(10)) { - let (unsuffixed, suffix) = split_suffix(&src, lit_kind); + let (unsuffixed, suffix) = split_suffix(src, lit_kind); let float = matches!(lit_kind, LitKind::Float(..)); Some(NumericLiteral::new(unsuffixed, suffix, float)) } else { diff --git a/src/tools/clippy/clippy_utils/src/ptr.rs b/src/tools/clippy/clippy_utils/src/ptr.rs index 5885cc83560..791688cd194 100644 --- a/src/tools/clippy/clippy_utils/src/ptr.rs +++ b/src/tools/clippy/clippy_utils/src/ptr.rs @@ -55,7 +55,7 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> { if self.abort { return; } - if let ExprKind::MethodCall(ref seg, _, ref args, _) = expr.kind { + if let ExprKind::MethodCall(seg, _, args, _) = expr.kind { if args.len() == 1 && match_var(&args[0], self.name) { if seg.ident.name.as_str() == "capacity" { self.abort = true; @@ -79,5 +79,5 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> { } fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> { - get_pat_name(&arg.pat) + get_pat_name(arg.pat) } diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index a08dcf19e5b..0e6ead675c2 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -255,7 +255,7 @@ fn check_place(tcx: TyCtxt<'tcx>, place: Place<'tcx>, span: Span, body: &Body<'t cursor = proj_base; match elem { ProjectionElem::Field(..) => { - let base_ty = Place::ty_from(place.local, &proj_base, body, tcx).ty; + let base_ty = Place::ty_from(place.local, proj_base, body, tcx).ty; if let Some(def) = base_ty.ty_adt_def() { // No union field accesses in `const fn` if def.is_union() { diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 0633a19391f..efc0ec50fdc 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -2,7 +2,7 @@ #![deny(clippy::missing_docs_in_private_items)] use crate::higher; -use crate::source::{snippet, snippet_opt, snippet_with_macro_callsite}; +use crate::source::{snippet, snippet_opt, snippet_with_context, snippet_with_macro_callsite}; use rustc_ast::util::parser::AssocOp; use rustc_ast::{ast, token}; use rustc_ast_pretty::pprust::token_kind_to_string; @@ -10,7 +10,7 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_lint::{EarlyContext, LateContext, LintContext}; use rustc_span::source_map::{CharPos, Span}; -use rustc_span::{BytePos, Pos}; +use rustc_span::{BytePos, Pos, SyntaxContext}; use std::borrow::Cow; use std::convert::TryInto; use std::fmt::Display; @@ -90,6 +90,29 @@ impl<'a> Sugg<'a> { Self::hir_from_snippet(expr, snippet) } + /// Same as `hir`, but first walks the span up to the given context. This will result in the + /// macro call, rather then the expansion, if the span is from a child context. If the span is + /// not from a child context, it will be used directly instead. + /// + /// e.g. Given the expression `&vec![]`, getting a snippet from the span for `vec![]` as a HIR + /// node would result in `box []`. If given the context of the address of expression, this + /// function will correctly get a snippet of `vec![]`. + pub fn hir_with_context( + cx: &LateContext<'_>, + expr: &hir::Expr<'_>, + ctxt: SyntaxContext, + default: &'a str, + applicability: &mut Applicability, + ) -> Self { + let (snippet, in_macro) = snippet_with_context(cx, expr.span, ctxt, default, applicability); + + if in_macro { + Sugg::NonParen(snippet) + } else { + Self::hir_from_snippet(expr, snippet) + } + } + /// Generate a suggestion for an expression with the given snippet. This is used by the `hir_*` /// function variants of `Sugg`, since these use different snippet functions. fn hir_from_snippet(expr: &hir::Expr<'_>, snippet: Cow<'a, str>) -> Self { @@ -289,7 +312,7 @@ fn has_enclosing_paren(sugg: impl AsRef<str>) -> bool { let mut chars = sugg.as_ref().chars(); if let Some('(') = chars.next() { let mut depth = 1; - while let Some(c) = chars.next() { + for c in &mut chars { if c == '(' { depth += 1; } else if c == ')' { @@ -684,7 +707,7 @@ impl<T: LintContext> DiagnosticBuilderExt<T> for rustc_errors::DiagnosticBuilder if let Some(non_whitespace_offset) = non_whitespace_offset { remove_span = remove_span - .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large"))) + .with_hi(remove_span.hi() + BytePos(non_whitespace_offset.try_into().expect("offset too large"))); } } diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 64a80f2554f..a92d3be5d3c 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -2,9 +2,8 @@ #![allow(clippy::module_name_repetitions)] -use std::collections::HashMap; - use rustc_ast::ast::Mutability; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{TyKind, Unsafety}; @@ -143,21 +142,18 @@ pub fn has_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { // Returns whether the type has #[must_use] attribute pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { match ty.kind() { - ty::Adt(ref adt, _) => must_use_attr(&cx.tcx.get_attrs(adt.did)).is_some(), - ty::Foreign(ref did) => must_use_attr(&cx.tcx.get_attrs(*did)).is_some(), - ty::Slice(ref ty) - | ty::Array(ref ty, _) - | ty::RawPtr(ty::TypeAndMut { ref ty, .. }) - | ty::Ref(_, ref ty, _) => { + ty::Adt(adt, _) => must_use_attr(cx.tcx.get_attrs(adt.did)).is_some(), + ty::Foreign(ref did) => must_use_attr(cx.tcx.get_attrs(*did)).is_some(), + ty::Slice(ty) | ty::Array(ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) | ty::Ref(_, ty, _) => { // for the Array case we don't need to care for the len == 0 case // because we don't want to lint functions returning empty arrays is_must_use_ty(cx, *ty) }, - ty::Tuple(ref substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), + ty::Tuple(substs) => substs.types().any(|ty| is_must_use_ty(cx, ty)), ty::Opaque(ref def_id, _) => { for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { if let ty::PredicateKind::Trait(trait_predicate, _) = predicate.kind().skip_binder() { - if must_use_attr(&cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() { + if must_use_attr(cx.tcx.get_attrs(trait_predicate.trait_ref.def_id)).is_some() { return true; } } @@ -167,7 +163,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { ty::Dynamic(binder, _) => { for predicate in binder.iter() { if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder() { - if must_use_attr(&cx.tcx.get_attrs(trait_ref.def_id)).is_some() { + if must_use_attr(cx.tcx.get_attrs(trait_ref.def_id)).is_some() { return true; } } @@ -184,14 +180,14 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { /// Checks if `Ty` is normalizable. This function is useful /// to avoid crashes on `layout_of`. pub fn is_normalizable<'tcx>(cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool { - is_normalizable_helper(cx, param_env, ty, &mut HashMap::new()) + is_normalizable_helper(cx, param_env, ty, &mut FxHashMap::default()) } fn is_normalizable_helper<'tcx>( cx: &LateContext<'tcx>, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>, - cache: &mut HashMap<Ty<'tcx>, bool>, + cache: &mut FxHashMap<Ty<'tcx>, bool>, ) -> bool { if let Some(&cached_result) = cache.get(ty) { return cached_result; @@ -306,7 +302,7 @@ pub fn type_is_unsafe_function<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bo /// Returns the base type for HIR references and pointers. pub fn walk_ptrs_hir_ty<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> &'tcx hir::Ty<'tcx> { match ty.kind { - TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(&mut_ty.ty), + TyKind::Ptr(ref mut_ty) | TyKind::Rptr(_, ref mut_ty) => walk_ptrs_hir_ty(mut_ty.ty), _ => ty, } } @@ -322,3 +318,27 @@ pub fn walk_ptrs_ty_depth(ty: Ty<'_>) -> (Ty<'_>, usize) { } inner(ty, 0) } + +/// Returns `true` if types `a` and `b` are same types having same `Const` generic args, +/// otherwise returns `false` +pub fn same_type_and_consts(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { + match (&a.kind(), &b.kind()) { + (&ty::Adt(did_a, substs_a), &ty::Adt(did_b, substs_b)) => { + if did_a != did_b { + return false; + } + + substs_a + .iter() + .zip(substs_b.iter()) + .all(|(arg_a, arg_b)| match (arg_a.unpack(), arg_b.unpack()) { + (GenericArgKind::Const(inner_a), GenericArgKind::Const(inner_b)) => inner_a == inner_b, + (GenericArgKind::Type(type_a), GenericArgKind::Type(type_b)) => { + same_type_and_consts(type_a, type_b) + }, + _ => true, + }) + }, + _ => a == b, + } +} diff --git a/src/tools/clippy/clippy_utils/src/usage.rs b/src/tools/clippy/clippy_utils/src/usage.rs index 650b70c63af..2c55021ac88 100644 --- a/src/tools/clippy/clippy_utils/src/usage.rs +++ b/src/tools/clippy/clippy_utils/src/usage.rs @@ -59,7 +59,7 @@ impl<'tcx> MutVarsDelegate { //FIXME: This causes false negatives. We can't get the `NodeId` from //`Categorization::Upvar(_)`. So we search for any `Upvar`s in the //`while`-body, not just the ones in the condition. - self.skip = true + self.skip = true; }, _ => {}, } @@ -71,12 +71,12 @@ impl<'tcx> Delegate<'tcx> for MutVarsDelegate { fn borrow(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId, bk: ty::BorrowKind) { if let ty::BorrowKind::MutBorrow = bk { - self.update(&cmt) + self.update(cmt); } } fn mutate(&mut self, cmt: &PlaceWithHirId<'tcx>, _: HirId) { - self.update(&cmt) + self.update(cmt); } fn fake_read(&mut self, _: rustc_typeck::expr_use_visitor::Place<'tcx>, _: FakeReadCause, _: HirId) {} diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index d431bdf34ee..ce00106dd4d 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -1,7 +1,7 @@ use crate::path_to_local_id; use rustc_hir as hir; use rustc_hir::intravisit::{self, walk_expr, ErasedMap, NestedVisitorMap, Visitor}; -use rustc_hir::{Arm, Block, Body, Destination, Expr, ExprKind, HirId, Stmt}; +use rustc_hir::{def::Res, Arm, Block, Body, BodyId, Destination, Expr, ExprKind, HirId, Stmt}; use rustc_lint::LateContext; use rustc_middle::hir::map::Map; @@ -87,7 +87,7 @@ where } fn visit_stmt(&mut self, stmt: &'hir hir::Stmt<'_>) { - intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt) + intravisit::walk_stmt(&mut *self.inside_stmt(true), stmt); } fn visit_expr(&mut self, expr: &'hir hir::Expr<'_>) { @@ -189,35 +189,23 @@ impl<'v> Visitor<'v> for LocalUsedVisitor<'v> { } } +/// A type which can be visited. pub trait Visitable<'tcx> { - fn visit<V: Visitor<'tcx>>(self, v: &mut V); + /// Calls the corresponding `visit_*` function on the visitor. + fn visit<V: Visitor<'tcx>>(self, visitor: &mut V); } -impl Visitable<'tcx> for &'tcx Expr<'tcx> { - fn visit<V: Visitor<'tcx>>(self, v: &mut V) { - v.visit_expr(self) - } -} -impl Visitable<'tcx> for &'tcx Block<'tcx> { - fn visit<V: Visitor<'tcx>>(self, v: &mut V) { - v.visit_block(self) - } -} -impl<'tcx> Visitable<'tcx> for &'tcx Stmt<'tcx> { - fn visit<V: Visitor<'tcx>>(self, v: &mut V) { - v.visit_stmt(self) - } -} -impl<'tcx> Visitable<'tcx> for &'tcx Body<'tcx> { - fn visit<V: Visitor<'tcx>>(self, v: &mut V) { - v.visit_body(self) - } -} -impl<'tcx> Visitable<'tcx> for &'tcx Arm<'tcx> { - fn visit<V: Visitor<'tcx>>(self, v: &mut V) { - v.visit_arm(self) - } +macro_rules! visitable_ref { + ($t:ident, $f:ident) => { + impl Visitable<'tcx> for &'tcx $t<'tcx> { + fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) { + visitor.$f(self); + } + } + }; } +visitable_ref!(Block, visit_block); +/// Calls the given function for each break expression. pub fn visit_break_exprs<'tcx>( node: impl Visitable<'tcx>, f: impl FnMut(&'tcx Expr<'tcx>, Destination, Option<&'tcx Expr<'tcx>>), @@ -231,7 +219,7 @@ pub fn visit_break_exprs<'tcx>( fn visit_expr(&mut self, e: &'tcx Expr<'_>) { if let ExprKind::Break(dest, sub_expr) = e.kind { - self.0(e, dest, sub_expr) + self.0(e, dest, sub_expr); } walk_expr(self, e); } @@ -239,3 +227,36 @@ pub fn visit_break_exprs<'tcx>( node.visit(&mut V(f)); } + +/// Checks if the given resolved path is used in the given body. +pub fn is_res_used(cx: &LateContext<'_>, res: Res, body: BodyId) -> bool { + struct V<'a, 'tcx> { + cx: &'a LateContext<'tcx>, + res: Res, + found: bool, + } + impl Visitor<'tcx> for V<'_, 'tcx> { + type Map = Map<'tcx>; + fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> { + NestedVisitorMap::OnlyBodies(self.cx.tcx.hir()) + } + + fn visit_expr(&mut self, e: &'tcx Expr<'_>) { + if self.found { + return; + } + + if let ExprKind::Path(p) = &e.kind { + if self.cx.qpath_res(p, e.hir_id) == self.res { + self.found = true; + } + } else { + walk_expr(self, e); + } + } + } + + let mut v = V { cx, res, found: false }; + v.visit_expr(&cx.tcx.hir().body(body).value); + v.found +} diff --git a/src/tools/clippy/doc/basics.md b/src/tools/clippy/doc/basics.md index 5226875cc21..e2e307ce4f6 100644 --- a/src/tools/clippy/doc/basics.md +++ b/src/tools/clippy/doc/basics.md @@ -28,6 +28,8 @@ git clone git@github.com:<your-username>/rust-clippy If you've already cloned Clippy in the past, update it to the latest version: ```bash +# If the upstream remote has not been added yet +git remote add upstream https://github.com/rust-lang/rust-clippy # upstream has to be the remote of the rust-lang/rust-clippy repo git fetch upstream # make sure that you are on the master branch diff --git a/src/tools/clippy/doc/release.md b/src/tools/clippy/doc/release.md index eaa6a9af277..e0af9bf0625 100644 --- a/src/tools/clippy/doc/release.md +++ b/src/tools/clippy/doc/release.md @@ -94,7 +94,7 @@ After finding the Clippy commit, it can be tagged with the release number. # Assuming the current directory corresponds to the Clippy repository $ git checkout $SHA $ git tag rust-1.XX.0 # XX should be exchanged with the corresponding version -$ git push upstream master --tags # `upstream` is the `rust-lang/rust-clippy` remote +$ git push upstream rust-1.XX.0 # `upstream` is the `rust-lang/rust-clippy` remote ``` After this, the release should be available on the Clippy [release page]. diff --git a/src/tools/clippy/mini-macro/Cargo.toml b/src/tools/clippy/mini-macro/Cargo.toml deleted file mode 100644 index 0d95c86aef0..00000000000 --- a/src/tools/clippy/mini-macro/Cargo.toml +++ /dev/null @@ -1,14 +0,0 @@ -[package] -name = "clippy-mini-macro-test" -version = "0.2.0" -authors = ["The Rust Clippy Developers"] -license = "MIT OR Apache-2.0" -description = "A macro to test clippy's procedural macro checks" -repository = "https://github.com/rust-lang/rust-clippy" -edition = "2018" - -[lib] -name = "clippy_mini_macro_test" -proc-macro = true - -[dependencies] diff --git a/src/tools/clippy/mini-macro/src/lib.rs b/src/tools/clippy/mini-macro/src/lib.rs deleted file mode 100644 index 2b793589049..00000000000 --- a/src/tools/clippy/mini-macro/src/lib.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![feature(proc_macro_quote)] -#![deny(rust_2018_idioms)] -// FIXME: Remove this attribute once the weird failure is gone. -#![allow(unused_extern_crates)] -extern crate proc_macro; - -use proc_macro::{quote, TokenStream}; - -#[proc_macro_derive(ClippyMiniMacroTest)] -/// # Panics -/// -/// Panics if the macro derivation fails -pub fn mini_macro(_: TokenStream) -> TokenStream { - quote!( - #[allow(unused)] - fn needless_take_by_value(s: String) { - println!("{}", s.len()); - } - #[allow(unused)] - fn needless_loop(items: &[u8]) { - for i in 0..items.len() { - println!("{}", items[i]); - } - } - fn line_wrapper() { - println!("{}", line!()); - } - ) -} diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 593162f09a7..e3863c46288 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2021-05-06" +channel = "nightly-2021-06-03" components = ["llvm-tools-preview", "rustc-dev", "rust-src"] diff --git a/src/tools/clippy/rustc_tools_util/src/lib.rs b/src/tools/clippy/rustc_tools_util/src/lib.rs index ff2a7de5725..5f289918a7c 100644 --- a/src/tools/clippy/rustc_tools_util/src/lib.rs +++ b/src/tools/clippy/rustc_tools_util/src/lib.rs @@ -100,9 +100,9 @@ pub fn get_commit_date() -> Option<String> { } #[must_use] -pub fn get_channel() -> Option<String> { +pub fn get_channel() -> String { match env::var("CFG_RELEASE_CHANNEL") { - Ok(channel) => Some(channel), + Ok(channel) => channel, Err(_) => { // if that failed, try to ask rustc -V, do some parsing and find out match std::process::Command::new("rustc") @@ -113,16 +113,16 @@ pub fn get_channel() -> Option<String> { { Some(rustc_output) => { if rustc_output.contains("beta") { - Some(String::from("beta")) + String::from("beta") } else if rustc_output.contains("stable") { - Some(String::from("stable")) + String::from("stable") } else { // default to nightly if we fail to parse - Some(String::from("nightly")) + String::from("nightly") } }, // default to nightly - None => Some(String::from("nightly")), + None => String::from("nightly"), } }, } diff --git a/src/tools/clippy/tests/clippy.toml b/src/tools/clippy/tests/clippy.toml new file mode 100644 index 00000000000..5eb7ac03541 --- /dev/null +++ b/src/tools/clippy/tests/clippy.toml @@ -0,0 +1 @@ +# default config for tests, overrides clippy.toml at the project root diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index e1110721f6e..7d266a36bb6 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -4,8 +4,8 @@ use compiletest_rs as compiletest; use compiletest_rs::common::Mode as TestMode; -use std::env::{self, set_var, var}; -use std::ffi::OsStr; +use std::env::{self, remove_var, set_var, var_os}; +use std::ffi::{OsStr, OsString}; use std::fs; use std::io; use std::path::{Path, PathBuf}; @@ -88,9 +88,11 @@ fn default_config() -> compiletest::Config { config } -fn run_mode(cfg: &mut compiletest::Config) { +fn run_ui(cfg: &mut compiletest::Config) { cfg.mode = TestMode::Ui; cfg.src_base = Path::new("tests").join("ui"); + // use tests/clippy.toml + let _g = VarGuard::set("CARGO_MANIFEST_DIR", std::fs::canonicalize("tests").unwrap()); compiletest::run_tests(cfg); } @@ -114,7 +116,7 @@ fn run_ui_toml(config: &mut compiletest::Config) { continue; } let dir_path = dir.path(); - set_var("CARGO_MANIFEST_DIR", &dir_path); + let _g = VarGuard::set("CARGO_MANIFEST_DIR", &dir_path); for file in fs::read_dir(&dir_path)? { let file = file?; let file_path = file.path(); @@ -145,9 +147,7 @@ fn run_ui_toml(config: &mut compiletest::Config) { let tests = compiletest::make_tests(config); - let manifest_dir = var("CARGO_MANIFEST_DIR").unwrap_or_default(); let res = run_tests(config, tests); - set_var("CARGO_MANIFEST_DIR", &manifest_dir); match res { Ok(true) => {}, Ok(false) => panic!("Some tests failed"), @@ -208,7 +208,7 @@ fn run_ui_cargo(config: &mut compiletest::Config) { Some("main.rs") => {}, _ => continue, } - set_var("CLIPPY_CONF_DIR", case.path()); + let _g = VarGuard::set("CLIPPY_CONF_DIR", case.path()); let paths = compiletest::common::TestPaths { file: file_path, base: config.src_base.clone(), @@ -236,10 +236,8 @@ fn run_ui_cargo(config: &mut compiletest::Config) { let tests = compiletest::make_tests(config); let current_dir = env::current_dir().unwrap(); - let conf_dir = var("CLIPPY_CONF_DIR").unwrap_or_default(); let res = run_tests(config, &config.filters, tests); env::set_current_dir(current_dir).unwrap(); - set_var("CLIPPY_CONF_DIR", conf_dir); match res { Ok(true) => {}, @@ -260,8 +258,32 @@ fn prepare_env() { fn compile_test() { prepare_env(); let mut config = default_config(); - run_mode(&mut config); + run_ui(&mut config); run_ui_toml(&mut config); run_ui_cargo(&mut config); run_internal_tests(&mut config); } + +/// Restores an env var on drop +#[must_use] +struct VarGuard { + key: &'static str, + value: Option<OsString>, +} + +impl VarGuard { + fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self { + let value = var_os(key); + set_var(key, val); + Self { key, value } + } +} + +impl Drop for VarGuard { + fn drop(&mut self) { + match self.value.as_deref() { + None => remove_var(self.key), + Some(value) => set_var(self.key, value), + } + } +} diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs index 6524fd4706c..7de130c7dbe 100644 --- a/src/tools/clippy/tests/dogfood.rs +++ b/src/tools/clippy/tests/dogfood.rs @@ -22,14 +22,12 @@ fn dogfood_clippy() { return; } let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let enable_metadata_collection = std::env::var("ENABLE_METADATA_COLLECTION").unwrap_or_else(|_| "0".to_string()); let mut command = Command::new(&*CLIPPY_PATH); command .current_dir(root_dir) .env("CLIPPY_DOGFOOD", "1") .env("CARGO_INCREMENTAL", "0") - .env("ENABLE_METADATA_COLLECTION", &enable_metadata_collection) .arg("clippy") .arg("--all-targets") .arg("--all-features") @@ -157,10 +155,9 @@ fn dogfood_subprojects() { if cargo::is_rustc_test_suite() { return; } - let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); // NOTE: `path_dep` crate is omitted on purpose here - for d in &[ + for project in &[ "clippy_workspace_tests", "clippy_workspace_tests/src", "clippy_workspace_tests/subcrate", @@ -170,34 +167,80 @@ fn dogfood_subprojects() { "clippy_utils", "rustc_tools_util", ] { - let mut command = Command::new(&*CLIPPY_PATH); - command - .current_dir(root_dir.join(d)) - .env("CLIPPY_DOGFOOD", "1") - .env("CARGO_INCREMENTAL", "0") - .arg("clippy") - .arg("--all-targets") - .arg("--all-features") - .arg("--") - .args(&["-D", "clippy::all"]) - .args(&["-D", "clippy::pedantic"]) - .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir + run_clippy_for_project(project); + } - // internal lints only exist if we build with the internal-lints feature - if cfg!(feature = "internal-lints") { - command.args(&["-D", "clippy::internal"]); + // NOTE: Since tests run in parallel we can't run cargo commands on the same workspace at the + // same time, so we test this immediately after the dogfood for workspaces. + test_no_deps_ignores_path_deps_in_workspaces(); +} + +#[test] +#[ignore] +#[cfg(feature = "metadata-collector-lint")] +fn run_metadata_collection_lint() { + use std::fs::File; + use std::time::SystemTime; + + // Setup for validation + let metadata_output_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("util/gh-pages/metadata_collection.json"); + let start_time = SystemTime::now(); + + // Run collection as is + std::env::set_var("ENABLE_METADATA_COLLECTION", "1"); + run_clippy_for_project("clippy_lints"); + + // Check if cargo caching got in the way + if let Ok(file) = File::open(metadata_output_path) { + if let Ok(metadata) = file.metadata() { + if let Ok(last_modification) = metadata.modified() { + if last_modification > start_time { + // The output file has been modified. Most likely by a hungry + // metadata collection monster. So We'll return. + return; + } + } } + } - let output = command.output().unwrap(); + // Force cargo to invalidate the caches + filetime::set_file_mtime( + PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("clippy_lints/src/lib.rs"), + filetime::FileTime::now(), + ) + .unwrap(); - println!("status: {}", output.status); - println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); - println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + // Running the collection again + run_clippy_for_project("clippy_lints"); +} - assert!(output.status.success()); +fn run_clippy_for_project(project: &str) { + let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + + let mut command = Command::new(&*CLIPPY_PATH); + + command + .current_dir(root_dir.join(project)) + .env("CLIPPY_DOGFOOD", "1") + .env("CARGO_INCREMENTAL", "0") + .arg("clippy") + .arg("--all-targets") + .arg("--all-features") + .arg("--") + .args(&["-D", "clippy::all"]) + .args(&["-D", "clippy::pedantic"]) + .arg("-Cdebuginfo=0"); // disable debuginfo to generate less data in the target dir + + // internal lints only exist if we build with the internal-lints feature + if cfg!(feature = "internal-lints") { + command.args(&["-D", "clippy::internal"]); } - // NOTE: Since tests run in parallel we can't run cargo commands on the same workspace at the - // same time, so we test this immediately after the dogfood for workspaces. - test_no_deps_ignores_path_deps_in_workspaces(); + let output = command.output().unwrap(); + + println!("status: {}", output.status); + println!("stdout: {}", String::from_utf8_lossy(&output.stdout)); + println!("stderr: {}", String::from_utf8_lossy(&output.stderr)); + + assert!(output.status.success()); } 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 d83080b69f5..a7be00426c4 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 @@ -1,4 +1,4 @@ -error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1 +error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown field `foobar`, expected one of `avoid-breaking-exported-api`, `msrv`, `blacklisted-names`, `cognitive-complexity-threshold`, `cyclomatic-complexity-threshold`, `doc-valid-idents`, `too-many-arguments-threshold`, `type-complexity-threshold`, `single-char-binding-names-threshold`, `too-large-for-stack`, `enum-variant-name-threshold`, `enum-variant-size-threshold`, `verbose-bit-mask-threshold`, `literal-representation-threshold`, `trivial-copy-size-limit`, `pass-by-value-size-limit`, `too-many-lines-threshold`, `array-size-threshold`, `vec-box-size-threshold`, `max-trait-bounds`, `max-struct-bools`, `max-fn-params-bools`, `warn-on-all-wildcard-imports`, `disallowed-methods`, `unreadable-literal-lint-fractions`, `upper-case-acronyms-aggressive`, `cargo-ignore-publish`, `third-party` at line 5 column 1 error: aborting due to previous error diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs index aebeaf34679..4b7b7fec78f 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs @@ -53,3 +53,22 @@ pub fn derive_use_self(_input: TokenStream) -> proc_macro::TokenStream { } } } + +#[proc_macro_derive(ClippyMiniMacroTest)] +pub fn mini_macro(_: TokenStream) -> TokenStream { + quote!( + #[allow(unused)] + fn needless_take_by_value(s: String) { + println!("{}", s.len()); + } + #[allow(unused)] + fn needless_loop(items: &[u8]) { + for i in 0..items.len() { + println!("{}", items[i]); + } + } + fn line_wrapper() { + println!("{}", line!()); + } + ) +} diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs new file mode 100644 index 00000000000..780797e3c6a --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/auxiliary/ice-7272-aux.rs @@ -0,0 +1,14 @@ +pub fn warn<T>(_: T) {} + +macro_rules! define_macro { + ($d:tt $lower:ident $upper:ident) => { + #[macro_export] + macro_rules! $upper { + ($arg:tt) => { + $crate::$lower($arg) + }; + } + }; +} + +define_macro! {$ warn WARNING} diff --git a/src/tools/clippy/tests/ui/crashes/ice-7231.rs b/src/tools/clippy/tests/ui/crashes/ice-7231.rs new file mode 100644 index 00000000000..5595d8d1d62 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-7231.rs @@ -0,0 +1,10 @@ +// edition:2018 +#![allow(clippy::never_loop)] + +async fn f() { + loop { + break; + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-7272.rs b/src/tools/clippy/tests/ui/crashes/ice-7272.rs new file mode 100644 index 00000000000..57ab6ca14f8 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-7272.rs @@ -0,0 +1,12 @@ +// aux-build:ice-7272-aux.rs + +#![allow(clippy::no_effect)] + +extern crate ice_7272_aux; + +use ice_7272_aux::*; + +pub fn main() { + || WARNING!("Style changed!"); + || "}{"; +} diff --git a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs b/src/tools/clippy/tests/ui/crashes/procedural_macro.rs deleted file mode 100644 index c7468493380..00000000000 --- a/src/tools/clippy/tests/ui/crashes/procedural_macro.rs +++ /dev/null @@ -1,11 +0,0 @@ -#[macro_use] -extern crate clippy_mini_macro_test; - -#[deny(warnings)] -fn main() { - let x = Foo; - println!("{:?}", x); -} - -#[derive(ClippyMiniMacroTest, Debug)] -struct Foo; diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs index 2a948d60b10..cba7666c2d8 100644 --- a/src/tools/clippy/tests/ui/def_id_nocore.rs +++ b/src/tools/clippy/tests/ui/def_id_nocore.rs @@ -20,7 +20,7 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize { 0 } -pub struct A; +struct A; impl A { pub fn as_ref(self) -> &'static str { diff --git a/src/tools/clippy/tests/ui/deprecated.rs b/src/tools/clippy/tests/ui/deprecated.rs index dbf0b03af76..4ba9f0c1fcf 100644 --- a/src/tools/clippy/tests/ui/deprecated.rs +++ b/src/tools/clippy/tests/ui/deprecated.rs @@ -12,5 +12,7 @@ #[warn(clippy::unknown_clippy_lints)] #[warn(clippy::find_map)] #[warn(clippy::filter_map)] +#[warn(clippy::pub_enum_variant_names)] +#[warn(clippy::wrong_pub_self_convention)] fn main() {} diff --git a/src/tools/clippy/tests/ui/deprecated.stderr b/src/tools/clippy/tests/ui/deprecated.stderr index e5de839dbc5..03c9f438891 100644 --- a/src/tools/clippy/tests/ui/deprecated.stderr +++ b/src/tools/clippy/tests/ui/deprecated.stderr @@ -84,5 +84,17 @@ error: lint `clippy::filter_map` has been removed: this lint has been replaced b LL | #[warn(clippy::filter_map)] | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: lint `clippy::pub_enum_variant_names` has been removed: set the `avoid_breaking_exported_api` config option to `false` to enable the `enum_variant_names` lint for public items + --> $DIR/deprecated.rs:15:8 + | +LL | #[warn(clippy::pub_enum_variant_names)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: lint `clippy::wrong_pub_self_convention` has been removed: set the `avoid_breaking_exported_api` config option to `false` to enable the `wrong_self_convention` lint for public items + --> $DIR/deprecated.rs:16:8 + | +LL | #[warn(clippy::wrong_pub_self_convention)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs index 4fefc0b43f1..083f5143e6e 100644 --- a/src/tools/clippy/tests/ui/enum_variants.rs +++ b/src/tools/clippy/tests/ui/enum_variants.rs @@ -1,5 +1,4 @@ -#![feature(non_ascii_idents)] -#![warn(clippy::enum_variant_names, clippy::pub_enum_variant_names)] +#![warn(clippy::enum_variant_names)] #![allow(non_camel_case_types, clippy::upper_case_acronyms)] enum FakeCallType { @@ -97,8 +96,8 @@ pub enum PubSeall { WithOut, } -#[allow(clippy::pub_enum_variant_names)] -mod allowed { +#[allow(clippy::enum_variant_names)] +pub mod allowed { pub enum PubAllowed { SomeThis, SomeThat, diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr index ab7fff4507a..447fbb9e1bf 100644 --- a/src/tools/clippy/tests/ui/enum_variants.stderr +++ b/src/tools/clippy/tests/ui/enum_variants.stderr @@ -1,5 +1,5 @@ error: variant name ends with the enum's name - --> $DIR/enum_variants.rs:16:5 + --> $DIR/enum_variants.rs:15:5 | LL | cFoo, | ^^^^ @@ -7,25 +7,25 @@ LL | cFoo, = note: `-D clippy::enum-variant-names` implied by `-D warnings` error: variant name starts with the enum's name - --> $DIR/enum_variants.rs:27:5 + --> $DIR/enum_variants.rs:26:5 | LL | FoodGood, | ^^^^^^^^ error: variant name starts with the enum's name - --> $DIR/enum_variants.rs:28:5 + --> $DIR/enum_variants.rs:27:5 | LL | FoodMiddle, | ^^^^^^^^^^ error: variant name starts with the enum's name - --> $DIR/enum_variants.rs:29:5 + --> $DIR/enum_variants.rs:28:5 | LL | FoodBad, | ^^^^^^^ error: all variants have the same prefix: `Food` - --> $DIR/enum_variants.rs:26:1 + --> $DIR/enum_variants.rs:25:1 | LL | / enum Food { LL | | FoodGood, @@ -37,7 +37,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: all variants have the same prefix: `CallType` - --> $DIR/enum_variants.rs:36:1 + --> $DIR/enum_variants.rs:35:1 | LL | / enum BadCallType { LL | | CallTypeCall, @@ -49,7 +49,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: all variants have the same prefix: `Constant` - --> $DIR/enum_variants.rs:48:1 + --> $DIR/enum_variants.rs:47:1 | LL | / enum Consts { LL | | ConstantInt, @@ -61,7 +61,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: all variants have the same prefix: `With` - --> $DIR/enum_variants.rs:82:1 + --> $DIR/enum_variants.rs:81:1 | LL | / enum Seallll { LL | | WithOutCake, @@ -73,7 +73,7 @@ LL | | } = help: remove the prefixes and use full paths to the variants instead of glob imports error: all variants have the same prefix: `Prefix` - --> $DIR/enum_variants.rs:88:1 + --> $DIR/enum_variants.rs:87:1 | LL | / enum NonCaps { LL | | Prefix的, @@ -84,21 +84,8 @@ LL | | } | = help: remove the prefixes and use full paths to the variants instead of glob imports -error: all variants have the same prefix: `With` - --> $DIR/enum_variants.rs:94:1 - | -LL | / pub enum PubSeall { -LL | | WithOutCake, -LL | | WithOutTea, -LL | | WithOut, -LL | | } - | |_^ - | - = note: `-D clippy::pub-enum-variant-names` implied by `-D warnings` - = help: remove the prefixes and use full paths to the variants instead of glob imports - error: all variants have the same postfix: `IData` - --> $DIR/enum_variants.rs:137:1 + --> $DIR/enum_variants.rs:136:1 | LL | / enum IDataRequest { LL | | PutIData(String), @@ -110,7 +97,7 @@ LL | | } = help: remove the postfixes and use full paths to the variants instead of glob imports error: all variants have the same postfix: `HIData` - --> $DIR/enum_variants.rs:143:1 + --> $DIR/enum_variants.rs:142:1 | LL | / enum HIDataRequest { LL | | PutHIData(String), @@ -121,5 +108,5 @@ LL | | } | = help: remove the postfixes and use full paths to the variants instead of glob imports -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed index 2be2283e3fd..9e752311c67 100644 --- a/src/tools/clippy/tests/ui/eta.fixed +++ b/src/tools/clippy/tests/ui/eta.fixed @@ -48,6 +48,9 @@ fn main() { // See #515 let a: Option<Box<dyn (::std::ops::Deref<Target = [i32]>)>> = Some(vec![1i32, 2]).map(|v| -> Box<dyn (::std::ops::Deref<Target = [i32]>)> { Box::new(v) }); + + // issue #7224 + let _: Option<Vec<u32>> = Some(0).map(|_| vec![]); } trait TestTrait { diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs index f0373f9ccf6..44be4628cbd 100644 --- a/src/tools/clippy/tests/ui/eta.rs +++ b/src/tools/clippy/tests/ui/eta.rs @@ -48,6 +48,9 @@ fn main() { // See #515 let a: Option<Box<dyn (::std::ops::Deref<Target = [i32]>)>> = Some(vec![1i32, 2]).map(|v| -> Box<dyn (::std::ops::Deref<Target = [i32]>)> { Box::new(v) }); + + // issue #7224 + let _: Option<Vec<u32>> = Some(0).map(|_| vec![]); } trait TestTrait { diff --git a/src/tools/clippy/tests/ui/eta.stderr b/src/tools/clippy/tests/ui/eta.stderr index 57ed6527966..8795d3b42c6 100644 --- a/src/tools/clippy/tests/ui/eta.stderr +++ b/src/tools/clippy/tests/ui/eta.stderr @@ -33,7 +33,7 @@ LL | let e = Some(1u8).map(|a| generic(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `generic` error: redundant closure - --> $DIR/eta.rs:89:51 + --> $DIR/eta.rs:92:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); | ^^^^^^^^^^^ help: replace the closure with the method itself: `TestStruct::foo` @@ -41,43 +41,43 @@ LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.foo()); = note: `-D clippy::redundant-closure-for-method-calls` implied by `-D warnings` error: redundant closure - --> $DIR/eta.rs:91:51 + --> $DIR/eta.rs:94:51 | LL | let e = Some(TestStruct { some_ref: &i }).map(|a| a.trait_foo()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `TestTrait::trait_foo` error: redundant closure - --> $DIR/eta.rs:94:42 + --> $DIR/eta.rs:97:42 | LL | let e = Some(&mut vec![1, 2, 3]).map(|v| v.clear()); | ^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::vec::Vec::clear` error: redundant closure - --> $DIR/eta.rs:99:29 + --> $DIR/eta.rs:102:29 | LL | let e = Some("str").map(|s| s.to_string()); | ^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `std::string::ToString::to_string` error: redundant closure - --> $DIR/eta.rs:101:27 + --> $DIR/eta.rs:104:27 | LL | let e = Some('a').map(|s| s.to_uppercase()); | ^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_uppercase` error: redundant closure - --> $DIR/eta.rs:104:65 + --> $DIR/eta.rs:107:65 | LL | let e: std::vec::Vec<char> = vec!['a', 'b', 'c'].iter().map(|c| c.to_ascii_uppercase()).collect(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the method itself: `char::to_ascii_uppercase` error: redundant closure - --> $DIR/eta.rs:187:27 + --> $DIR/eta.rs:190:27 | LL | let a = Some(1u8).map(|a| foo_ptr(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `foo_ptr` error: redundant closure - --> $DIR/eta.rs:192:27 + --> $DIR/eta.rs:195:27 | LL | let a = Some(1u8).map(|a| closure(a)); | ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `closure` diff --git a/src/tools/clippy/tests/ui/floating_point_powi.fixed b/src/tools/clippy/tests/ui/floating_point_powi.fixed index 56762400593..85f7c531e39 100644 --- a/src/tools/clippy/tests/ui/floating_point_powi.fixed +++ b/src/tools/clippy/tests/ui/floating_point_powi.fixed @@ -4,8 +4,6 @@ fn main() { let one = 1; let x = 3f32; - let _ = x * x; - let _ = x * x; let y = 4f32; let _ = x.mul_add(x, y); @@ -13,7 +11,10 @@ fn main() { let _ = x.mul_add(x, y).sqrt(); let _ = y.mul_add(y, x).sqrt(); // Cases where the lint shouldn't be applied + let _ = x.powi(2); + let _ = x.powi(1 + 1); let _ = x.powi(3); + let _ = x.powi(4) + y; let _ = x.powi(one + 1); let _ = (x.powi(2) + y.powi(2)).sqrt(); } diff --git a/src/tools/clippy/tests/ui/floating_point_powi.rs b/src/tools/clippy/tests/ui/floating_point_powi.rs index 1f800e4628d..ece61d1bec4 100644 --- a/src/tools/clippy/tests/ui/floating_point_powi.rs +++ b/src/tools/clippy/tests/ui/floating_point_powi.rs @@ -4,8 +4,6 @@ fn main() { let one = 1; let x = 3f32; - let _ = x.powi(2); - let _ = x.powi(1 + 1); let y = 4f32; let _ = x.powi(2) + y; @@ -13,7 +11,10 @@ fn main() { let _ = (x.powi(2) + y).sqrt(); let _ = (x + y.powi(2)).sqrt(); // Cases where the lint shouldn't be applied + let _ = x.powi(2); + let _ = x.powi(1 + 1); let _ = x.powi(3); + let _ = x.powi(4) + y; let _ = x.powi(one + 1); let _ = (x.powi(2) + y.powi(2)).sqrt(); } diff --git a/src/tools/clippy/tests/ui/floating_point_powi.stderr b/src/tools/clippy/tests/ui/floating_point_powi.stderr index d5a5f1bcca1..37d840988bb 100644 --- a/src/tools/clippy/tests/ui/floating_point_powi.stderr +++ b/src/tools/clippy/tests/ui/floating_point_powi.stderr @@ -1,40 +1,28 @@ -error: square can be computed more efficiently - --> $DIR/floating_point_powi.rs:7:13 - | -LL | let _ = x.powi(2); - | ^^^^^^^^^ help: consider using: `x * x` - | - = note: `-D clippy::suboptimal-flops` implied by `-D warnings` - -error: square can be computed more efficiently - --> $DIR/floating_point_powi.rs:8:13 - | -LL | let _ = x.powi(1 + 1); - | ^^^^^^^^^^^^^ help: consider using: `x * x` - -error: square can be computed more efficiently - --> $DIR/floating_point_powi.rs:11:13 +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:9:13 | LL | let _ = x.powi(2) + y; | ^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` + | + = note: `-D clippy::suboptimal-flops` implied by `-D warnings` -error: square can be computed more efficiently - --> $DIR/floating_point_powi.rs:12:13 +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:10:13 | LL | let _ = x + y.powi(2); | ^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` -error: square can be computed more efficiently - --> $DIR/floating_point_powi.rs:13:13 +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:11:13 | LL | let _ = (x.powi(2) + y).sqrt(); | ^^^^^^^^^^^^^^^ help: consider using: `x.mul_add(x, y)` -error: square can be computed more efficiently - --> $DIR/floating_point_powi.rs:14:13 +error: multiply and add expressions can be calculated more efficiently and accurately + --> $DIR/floating_point_powi.rs:12:13 | LL | let _ = (x + y.powi(2)).sqrt(); | ^^^^^^^^^^^^^^^ help: consider using: `y.mul_add(y, x)` -error: aborting due to 6 previous errors +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed index b5f548810e6..12db43b5343 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed @@ -6,6 +6,20 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; use std::iter::FromIterator; +struct Foo(Vec<bool>); + +impl FromIterator<bool> for Foo { + fn from_iter<T: IntoIterator<Item = bool>>(_: T) -> Self { + todo!() + } +} + +impl<'a> FromIterator<&'a bool> for Foo { + fn from_iter<T: IntoIterator<Item = &'a bool>>(iter: T) -> Self { + iter.into_iter().copied().collect::<Self>() + } +} + fn main() { let iter_expr = std::iter::repeat(5).take(5); let _ = iter_expr.collect::<Vec<_>>(); diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs index b842b5451d1..f5ec190e0cd 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs @@ -6,6 +6,20 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, VecDeque}; use std::iter::FromIterator; +struct Foo(Vec<bool>); + +impl FromIterator<bool> for Foo { + fn from_iter<T: IntoIterator<Item = bool>>(_: T) -> Self { + todo!() + } +} + +impl<'a> FromIterator<&'a bool> for Foo { + fn from_iter<T: IntoIterator<Item = &'a bool>>(iter: T) -> Self { + <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied()) + } +} + fn main() { let iter_expr = std::iter::repeat(5).take(5); let _ = Vec::from_iter(iter_expr); diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr index 434734c9a21..8f08ac8c3ff 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.stderr @@ -1,88 +1,94 @@ error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:11:13 + --> $DIR/from_iter_instead_of_collect.rs:19:9 | -LL | let _ = Vec::from_iter(iter_expr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()` +LL | <Self as FromIterator<bool>>::from_iter(iter.into_iter().copied()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter.into_iter().copied().collect::<Self>()` | = note: `-D clippy::from-iter-instead-of-collect` implied by `-D warnings` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:13:13 + --> $DIR/from_iter_instead_of_collect.rs:25:13 + | +LL | let _ = Vec::from_iter(iter_expr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `iter_expr.collect::<Vec<_>>()` + +error: usage of `FromIterator::from_iter` + --> $DIR/from_iter_instead_of_collect.rs:27:13 | LL | let _ = HashMap::<usize, &i8>::from_iter(vec![5, 5, 5, 5].iter().enumerate()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `vec![5, 5, 5, 5].iter().enumerate().collect::<HashMap<usize, &i8>>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:18:19 + --> $DIR/from_iter_instead_of_collect.rs:32:19 | LL | assert_eq!(a, Vec::from_iter(0..3)); | ^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<_>>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:19:19 + --> $DIR/from_iter_instead_of_collect.rs:33:19 | LL | assert_eq!(a, Vec::<i32>::from_iter(0..3)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<Vec<i32>>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:21:17 + --> $DIR/from_iter_instead_of_collect.rs:35:17 | LL | let mut b = VecDeque::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<_>>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:24:17 + --> $DIR/from_iter_instead_of_collect.rs:38:17 | LL | let mut b = VecDeque::<i32>::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<VecDeque<i32>>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:29:21 + --> $DIR/from_iter_instead_of_collect.rs:43:21 | LL | let mut b = collections::VecDeque::<i32>::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::VecDeque<i32>>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:34:14 + --> $DIR/from_iter_instead_of_collect.rs:48:14 | LL | let bm = BTreeMap::from_iter(values.iter().cloned()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `values.iter().cloned().collect::<BTreeMap<_, _>>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:35:19 + --> $DIR/from_iter_instead_of_collect.rs:49:19 | LL | let mut bar = BTreeMap::from_iter(bm.range(0..2)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `bm.range(0..2).collect::<BTreeMap<_, _>>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:38:19 + --> $DIR/from_iter_instead_of_collect.rs:52:19 | LL | let mut bts = BTreeSet::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<BTreeSet<_>>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:42:17 + --> $DIR/from_iter_instead_of_collect.rs:56:17 | LL | let _ = collections::BTreeSet::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<_>>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:43:17 + --> $DIR/from_iter_instead_of_collect.rs:57:17 | LL | let _ = collections::BTreeSet::<u32>::from_iter(0..3); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `(0..3).collect::<collections::BTreeSet<u32>>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:46:15 + --> $DIR/from_iter_instead_of_collect.rs:60:15 | LL | for _i in Vec::from_iter([1, 2, 3].iter()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<_>>()` error: usage of `FromIterator::from_iter` - --> $DIR/from_iter_instead_of_collect.rs:47:15 + --> $DIR/from_iter_instead_of_collect.rs:61:15 | LL | for _i in Vec::<&i32>::from_iter([1, 2, 3].iter()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use `.collect()` instead of `::from_iter()`: `[1, 2, 3].iter().collect::<Vec<&i32>>()` -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/functions.stderr b/src/tools/clippy/tests/ui/functions.stderr index 0a86568b18d..a2b8c2a384b 100644 --- a/src/tools/clippy/tests/ui/functions.stderr +++ b/src/tools/clippy/tests/ui/functions.stderr @@ -30,7 +30,7 @@ error: this function has too many arguments (8/7) LL | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: this public function dereferences a raw pointer but is not marked `unsafe` +error: this public function might dereference a raw pointer but is not marked `unsafe` --> $DIR/functions.rs:63:34 | LL | println!("{}", unsafe { *p }); @@ -38,49 +38,49 @@ LL | println!("{}", unsafe { *p }); | = note: `-D clippy::not-unsafe-ptr-arg-deref` implied by `-D warnings` -error: this public function dereferences a raw pointer but is not marked `unsafe` +error: this public function might dereference a raw pointer but is not marked `unsafe` --> $DIR/functions.rs:64:35 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ -error: this public function dereferences a raw pointer but is not marked `unsafe` +error: this public function might dereference a raw pointer but is not marked `unsafe` --> $DIR/functions.rs:65:33 | LL | unsafe { std::ptr::read(p) }; | ^ -error: this public function dereferences a raw pointer but is not marked `unsafe` +error: this public function might dereference a raw pointer but is not marked `unsafe` --> $DIR/functions.rs:76:30 | LL | println!("{}", unsafe { *p }); | ^ -error: this public function dereferences a raw pointer but is not marked `unsafe` +error: this public function might dereference a raw pointer but is not marked `unsafe` --> $DIR/functions.rs:77:31 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ -error: this public function dereferences a raw pointer but is not marked `unsafe` +error: this public function might dereference a raw pointer but is not marked `unsafe` --> $DIR/functions.rs:78:29 | LL | unsafe { std::ptr::read(p) }; | ^ -error: this public function dereferences a raw pointer but is not marked `unsafe` +error: this public function might dereference a raw pointer but is not marked `unsafe` --> $DIR/functions.rs:87:34 | LL | println!("{}", unsafe { *p }); | ^ -error: this public function dereferences a raw pointer but is not marked `unsafe` +error: this public function might dereference a raw pointer but is not marked `unsafe` --> $DIR/functions.rs:88:35 | LL | println!("{:?}", unsafe { p.as_ref() }); | ^ -error: this public function dereferences a raw pointer but is not marked `unsafe` +error: this public function might dereference a raw pointer but is not marked `unsafe` --> $DIR/functions.rs:89:33 | LL | unsafe { std::ptr::read(p) }; diff --git a/src/tools/clippy/tests/ui/impl.rs b/src/tools/clippy/tests/ui/impl.rs index 1c46e3a5337..39443775015 100644 --- a/src/tools/clippy/tests/ui/impl.rs +++ b/src/tools/clippy/tests/ui/impl.rs @@ -33,4 +33,35 @@ impl fmt::Debug for MyStruct { } } +// issue #5772 +struct WithArgs<T>(T); +impl WithArgs<u32> { + fn f1() {} +} +impl WithArgs<u64> { + fn f2() {} +} +impl WithArgs<u64> { + fn f3() {} +} + +// Ok, the struct is allowed to have multiple impls. +#[allow(clippy::multiple_inherent_impl)] +struct Allowed; +impl Allowed {} +impl Allowed {} +impl Allowed {} + +struct AllowedImpl; +#[allow(clippy::multiple_inherent_impl)] +impl AllowedImpl {} +// Ok, the first block is skipped by this lint. +impl AllowedImpl {} + +struct OneAllowedImpl; +impl OneAllowedImpl {} +#[allow(clippy::multiple_inherent_impl)] +impl OneAllowedImpl {} +impl OneAllowedImpl {} // Lint, only one of the three blocks is allowed. + fn main() {} diff --git a/src/tools/clippy/tests/ui/impl.stderr b/src/tools/clippy/tests/ui/impl.stderr index aab688cc2d8..8703ecac93e 100644 --- a/src/tools/clippy/tests/ui/impl.stderr +++ b/src/tools/clippy/tests/ui/impl.stderr @@ -31,5 +31,33 @@ LL | | fn first() {} LL | | } | |_^ -error: aborting due to 2 previous errors +error: multiple implementations of this structure + --> $DIR/impl.rs:44:1 + | +LL | / impl WithArgs<u64> { +LL | | fn f3() {} +LL | | } + | |_^ + | +note: first implementation here + --> $DIR/impl.rs:41:1 + | +LL | / impl WithArgs<u64> { +LL | | fn f2() {} +LL | | } + | |_^ + +error: multiple implementations of this structure + --> $DIR/impl.rs:65:1 + | +LL | impl OneAllowedImpl {} // Lint, only one of the three blocks is allowed. + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: first implementation here + --> $DIR/impl.rs:62:1 + | +LL | impl OneAllowedImpl {} + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed index 51c66a46368..70d49d9f2c4 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.fixed +++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed @@ -1,6 +1,7 @@ // compile-flags: --edition 2018 // aux-build:macro_rules.rs // aux-build:macro_use_helper.rs +// aux-build:proc_macro_derive.rs // run-rustfix // ignore-32bit @@ -12,7 +13,7 @@ extern crate macro_use_helper as mac; #[macro_use] -extern crate clippy_mini_macro_test as mini_mac; +extern crate proc_macro_derive as mini_mac; mod a { use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro}; diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs index 2011129bc94..68370023861 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports.rs @@ -1,6 +1,7 @@ // compile-flags: --edition 2018 // aux-build:macro_rules.rs // aux-build:macro_use_helper.rs +// aux-build:proc_macro_derive.rs // run-rustfix // ignore-32bit @@ -12,7 +13,7 @@ extern crate macro_use_helper as mac; #[macro_use] -extern crate clippy_mini_macro_test as mini_mac; +extern crate proc_macro_derive as mini_mac; mod a { #[macro_use] diff --git a/src/tools/clippy/tests/ui/macro_use_imports.stderr b/src/tools/clippy/tests/ui/macro_use_imports.stderr index f8c86c8d917..49314b7506d 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.stderr +++ b/src/tools/clippy/tests/ui/macro_use_imports.stderr @@ -1,5 +1,5 @@ error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:18:5 + --> $DIR/macro_use_imports.rs:19:5 | LL | #[macro_use] | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{pub_macro, inner_mod_macro, function_macro, ty_macro, pub_in_private_macro};` @@ -7,22 +7,22 @@ LL | #[macro_use] = note: `-D clippy::macro-use-imports` implied by `-D warnings` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:20:5 + --> $DIR/macro_use_imports.rs:25:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:22:5 + --> $DIR/macro_use_imports.rs:21:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mini_mac::ClippyMiniMacroTest;` error: `macro_use` attributes are no longer needed in the Rust 2018 edition - --> $DIR/macro_use_imports.rs:24:5 + --> $DIR/macro_use_imports.rs:23:5 | LL | #[macro_use] - | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::inner::nested::string_add;` + | ^^^^^^^^^^^^ help: remove the attribute and import the macro directly, try: `use mac::{inner::foofoo, inner::try_err};` error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.fixed b/src/tools/clippy/tests/ui/manual_str_repeat.fixed new file mode 100644 index 00000000000..dc140257f32 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_str_repeat.fixed @@ -0,0 +1,66 @@ +// run-rustfix + +#![feature(custom_inner_attributes)] +#![warn(clippy::manual_str_repeat)] + +use std::borrow::Cow; +use std::iter::{repeat, FromIterator}; + +fn main() { + let _: String = "test".repeat(10); + let _: String = "x".repeat(10); + let _: String = "'".repeat(10); + let _: String = "\"".repeat(10); + + let x = "test"; + let count = 10; + let _ = x.repeat(count + 2); + + macro_rules! m { + ($e:expr) => {{ $e }}; + } + // FIXME: macro args are fine + let _: String = repeat(m!("test")).take(m!(count)).collect(); + + let x = &x; + let _: String = (*x).repeat(count); + + macro_rules! repeat_m { + ($e:expr) => {{ repeat($e) }}; + } + // Don't lint, repeat is from a macro. + let _: String = repeat_m!("test").take(count).collect(); + + let x: Box<str> = Box::from("test"); + let _: String = x.repeat(count); + + #[derive(Clone)] + struct S; + impl FromIterator<Box<S>> for String { + fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self { + Self::new() + } + } + // Don't lint, wrong box type + let _: String = repeat(Box::new(S)).take(count).collect(); + + let _: String = Cow::Borrowed("test").repeat(count); + + let x = "x".to_owned(); + let _: String = x.repeat(count); + + let x = 'x'; + // Don't lint, not char literal + let _: String = repeat(x).take(count).collect(); +} + +fn _msrv_1_15() { + #![clippy::msrv = "1.15"] + // `str::repeat` was stabilized in 1.16. Do not lint this + let _: String = std::iter::repeat("test").take(10).collect(); +} + +fn _msrv_1_16() { + #![clippy::msrv = "1.16"] + let _: String = "test".repeat(10); +} diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.rs b/src/tools/clippy/tests/ui/manual_str_repeat.rs new file mode 100644 index 00000000000..0d69c989b2e --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_str_repeat.rs @@ -0,0 +1,66 @@ +// run-rustfix + +#![feature(custom_inner_attributes)] +#![warn(clippy::manual_str_repeat)] + +use std::borrow::Cow; +use std::iter::{repeat, FromIterator}; + +fn main() { + let _: String = std::iter::repeat("test").take(10).collect(); + let _: String = std::iter::repeat('x').take(10).collect(); + let _: String = std::iter::repeat('\'').take(10).collect(); + let _: String = std::iter::repeat('"').take(10).collect(); + + let x = "test"; + let count = 10; + let _ = repeat(x).take(count + 2).collect::<String>(); + + macro_rules! m { + ($e:expr) => {{ $e }}; + } + // FIXME: macro args are fine + let _: String = repeat(m!("test")).take(m!(count)).collect(); + + let x = &x; + let _: String = repeat(*x).take(count).collect(); + + macro_rules! repeat_m { + ($e:expr) => {{ repeat($e) }}; + } + // Don't lint, repeat is from a macro. + let _: String = repeat_m!("test").take(count).collect(); + + let x: Box<str> = Box::from("test"); + let _: String = repeat(x).take(count).collect(); + + #[derive(Clone)] + struct S; + impl FromIterator<Box<S>> for String { + fn from_iter<T: IntoIterator<Item = Box<S>>>(_: T) -> Self { + Self::new() + } + } + // Don't lint, wrong box type + let _: String = repeat(Box::new(S)).take(count).collect(); + + let _: String = repeat(Cow::Borrowed("test")).take(count).collect(); + + let x = "x".to_owned(); + let _: String = repeat(x).take(count).collect(); + + let x = 'x'; + // Don't lint, not char literal + let _: String = repeat(x).take(count).collect(); +} + +fn _msrv_1_15() { + #![clippy::msrv = "1.15"] + // `str::repeat` was stabilized in 1.16. Do not lint this + let _: String = std::iter::repeat("test").take(10).collect(); +} + +fn _msrv_1_16() { + #![clippy::msrv = "1.16"] + let _: String = std::iter::repeat("test").take(10).collect(); +} diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.stderr b/src/tools/clippy/tests/ui/manual_str_repeat.stderr new file mode 100644 index 00000000000..c6511689716 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_str_repeat.stderr @@ -0,0 +1,64 @@ +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:10:21 + | +LL | let _: String = std::iter::repeat("test").take(10).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)` + | + = note: `-D clippy::manual-str-repeat` implied by `-D warnings` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:11:21 + | +LL | let _: String = std::iter::repeat('x').take(10).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"x".repeat(10)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:12:21 + | +LL | let _: String = std::iter::repeat('/'').take(10).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"'".repeat(10)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:13:21 + | +LL | let _: String = std::iter::repeat('"').take(10).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"/"".repeat(10)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:17:13 + | +LL | let _ = repeat(x).take(count + 2).collect::<String>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count + 2)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:26:21 + | +LL | let _: String = repeat(*x).take(count).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `(*x).repeat(count)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:35:21 + | +LL | let _: String = repeat(x).take(count).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:47:21 + | +LL | let _: String = repeat(Cow::Borrowed("test")).take(count).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Cow::Borrowed("test").repeat(count)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:50:21 + | +LL | let _: String = repeat(x).take(count).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `x.repeat(count)` + +error: manual implementation of `str::repeat` using iterators + --> $DIR/manual_str_repeat.rs:65:21 + | +LL | let _: String = std::iter::repeat("test").take(10).collect(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `"test".repeat(10)` + +error: aborting due to 10 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed index e7a29596b73..3717f962745 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed @@ -163,4 +163,19 @@ mod issue6965 { } } +use std::rc::Rc; +fn format_name(name: Option<&Rc<str>>) -> &str { + match name { + None => "<anon>", + Some(name) => name, + } +} + +fn implicit_deref_ref() { + let _: &str = match Some(&"bye") { + None => "hi", + Some(s) => s, + }; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.rs b/src/tools/clippy/tests/ui/manual_unwrap_or.rs index 66006b6c616..989adde1f5b 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.rs +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.rs @@ -205,4 +205,19 @@ mod issue6965 { } } +use std::rc::Rc; +fn format_name(name: Option<&Rc<str>>) -> &str { + match name { + None => "<anon>", + Some(name) => name, + } +} + +fn implicit_deref_ref() { + let _: &str = match Some(&"bye") { + None => "hi", + Some(s) => s, + }; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed index 526e94b10bd..30bf6402253 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.fixed +++ b/src/tools/clippy/tests/ui/match_single_binding.fixed @@ -94,10 +94,7 @@ fn main() { 0 => println!("Disabled branch"), _ => println!("Enabled branch"), } - // Lint - let x = 1; - let y = 1; - println!("Single branch"); + // Ok let x = 1; let y = 1; diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs index 6a2ca7c5e93..d8bb80d8b96 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.rs +++ b/src/tools/clippy/tests/ui/match_single_binding.rs @@ -106,15 +106,7 @@ fn main() { 0 => println!("Disabled branch"), _ => println!("Enabled branch"), } - // Lint - let x = 1; - let y = 1; - match match y { - 0 => 1, - _ => 2, - } { - _ => println!("Single branch"), - } + // Ok let x = 1; let y = 1; diff --git a/src/tools/clippy/tests/ui/match_single_binding.stderr b/src/tools/clippy/tests/ui/match_single_binding.stderr index cbbf5d29c02..795c8c3e24d 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.stderr +++ b/src/tools/clippy/tests/ui/match_single_binding.stderr @@ -167,16 +167,5 @@ LL | unwrapped LL | }) | -error: this match could be replaced by its body itself - --> $DIR/match_single_binding.rs:112:5 - | -LL | / match match y { -LL | | 0 => 1, -LL | | _ => 2, -LL | | } { -LL | | _ => println!("Single branch"), -LL | | } - | |_____^ help: consider using the match body instead: `println!("Single branch");` - -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/match_single_binding2.fixed b/src/tools/clippy/tests/ui/match_single_binding2.fixed index e73a85b73d7..a91fcc2125d 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.fixed +++ b/src/tools/clippy/tests/ui/match_single_binding2.fixed @@ -34,4 +34,20 @@ fn main() { }, None => println!("nothing"), } + + fn side_effects() {} + + // Lint (scrutinee has side effects) + // issue #7094 + side_effects(); + println!("Side effects"); + + // Lint (scrutinee has side effects) + // issue #7094 + let x = 1; + match x { + 0 => 1, + _ => 2, + }; + println!("Single branch"); } diff --git a/src/tools/clippy/tests/ui/match_single_binding2.rs b/src/tools/clippy/tests/ui/match_single_binding2.rs index 7362cb390e5..476386ebabe 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.rs +++ b/src/tools/clippy/tests/ui/match_single_binding2.rs @@ -34,4 +34,22 @@ fn main() { }, None => println!("nothing"), } + + fn side_effects() {} + + // Lint (scrutinee has side effects) + // issue #7094 + match side_effects() { + _ => println!("Side effects"), + } + + // Lint (scrutinee has side effects) + // issue #7094 + let x = 1; + match match x { + 0 => 1, + _ => 2, + } { + _ => println!("Single branch"), + } } diff --git a/src/tools/clippy/tests/ui/match_single_binding2.stderr b/src/tools/clippy/tests/ui/match_single_binding2.stderr index bc18d191aa3..4372f55af87 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.stderr +++ b/src/tools/clippy/tests/ui/match_single_binding2.stderr @@ -30,5 +30,39 @@ LL | let (a, b) = get_tup(); LL | println!("a {:?} and b {:?}", a, b); | -error: aborting due to 2 previous errors +error: this match could be replaced by its scrutinee and body + --> $DIR/match_single_binding2.rs:42:5 + | +LL | / match side_effects() { +LL | | _ => println!("Side effects"), +LL | | } + | |_____^ + | +help: consider using the scrutinee and body instead + | +LL | side_effects(); +LL | println!("Side effects"); + | + +error: this match could be replaced by its scrutinee and body + --> $DIR/match_single_binding2.rs:49:5 + | +LL | / match match x { +LL | | 0 => 1, +LL | | _ => 2, +LL | | } { +LL | | _ => println!("Single branch"), +LL | | } + | |_____^ + | +help: consider using the scrutinee and body instead + | +LL | match x { +LL | 0 => 1, +LL | _ => 2, +LL | }; +LL | println!("Single branch"); + | + +error: aborting due to 4 previous errors diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.rs b/src/tools/clippy/tests/ui/missing-doc-impl.rs index 57af84dcdf4..bfa9ef01b0e 100644 --- a/src/tools/clippy/tests/ui/missing-doc-impl.rs +++ b/src/tools/clippy/tests/ui/missing-doc-impl.rs @@ -67,7 +67,10 @@ impl PubFoo { pub fn foo() {} /// dox pub fn foo1() {} - fn foo2() {} + #[must_use = "yep"] + fn foo2() -> u32 { + 1 + } #[allow(clippy::missing_docs_in_private_items)] pub fn foo3() {} } diff --git a/src/tools/clippy/tests/ui/missing-doc-impl.stderr b/src/tools/clippy/tests/ui/missing-doc-impl.stderr index 7e10404ca00..d33d512475b 100644 --- a/src/tools/clippy/tests/ui/missing-doc-impl.stderr +++ b/src/tools/clippy/tests/ui/missing-doc-impl.stderr @@ -94,10 +94,12 @@ LL | pub fn foo() {} | ^^^^^^^^^^^^^^^ error: missing documentation for an associated function - --> $DIR/missing-doc-impl.rs:70:5 + --> $DIR/missing-doc-impl.rs:71:5 | -LL | fn foo2() {} - | ^^^^^^^^^^^^ +LL | / fn foo2() -> u32 { +LL | | 1 +LL | | } + | |_____^ error: aborting due to 15 previous errors diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.rs b/src/tools/clippy/tests/ui/module_name_repetitions.rs index 669bf01a84c..f5908cb5701 100644 --- a/src/tools/clippy/tests/ui/module_name_repetitions.rs +++ b/src/tools/clippy/tests/ui/module_name_repetitions.rs @@ -15,12 +15,4 @@ mod foo { pub struct Foobar; } -#[cfg(test)] -mod test { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} - fn main() {} diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed new file mode 100644 index 00000000000..5e1ea663a10 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed @@ -0,0 +1,40 @@ +// run-rustfix + +#![warn(clippy::needless_bitwise_bool)] + +fn returns_bool() -> bool { + true +} + +const fn const_returns_bool() -> bool { + false +} + +fn main() { + let (x, y) = (false, true); + if x & y { + println!("true") + } + if returns_bool() & x { + println!("true") + } + if !returns_bool() & returns_bool() { + println!("true") + } + if y && !x { + println!("true") + } + + // BELOW: lints we hope to catch as `Expr::can_have_side_effects` improves. + if y & !const_returns_bool() { + println!("true") // This is a const function, in an UnOp + } + + if y & "abcD".is_empty() { + println!("true") // This is a const method call + } + + if y & (0 < 1) { + println!("true") // This is a BinOp with no side effects + } +} diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs new file mode 100644 index 00000000000..f3075fba0a2 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs @@ -0,0 +1,40 @@ +// run-rustfix + +#![warn(clippy::needless_bitwise_bool)] + +fn returns_bool() -> bool { + true +} + +const fn const_returns_bool() -> bool { + false +} + +fn main() { + let (x, y) = (false, true); + if x & y { + println!("true") + } + if returns_bool() & x { + println!("true") + } + if !returns_bool() & returns_bool() { + println!("true") + } + if y & !x { + println!("true") + } + + // BELOW: lints we hope to catch as `Expr::can_have_side_effects` improves. + if y & !const_returns_bool() { + println!("true") // This is a const function, in an UnOp + } + + if y & "abcD".is_empty() { + println!("true") // This is a const method call + } + + if y & (0 < 1) { + println!("true") // This is a BinOp with no side effects + } +} diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr new file mode 100644 index 00000000000..63c88ef63f5 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.stderr @@ -0,0 +1,10 @@ +error: use of bitwise operator instead of lazy operator between booleans + --> $DIR/needless_bitwise_bool.rs:24:8 + | +LL | if y & !x { + | ^^^^^^ help: try: `y && !x` + | + = note: `-D clippy::needless-bitwise-bool` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed index 5ae4a0e79b9..a87171dc3f2 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.fixed +++ b/src/tools/clippy/tests/ui/needless_borrow.fixed @@ -18,7 +18,6 @@ fn main() { let vec = Vec::new(); let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]` h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait` - if let Some(cake) = Some(&5) {} let garbl = match 42 { 44 => &a, 45 => { @@ -43,19 +42,3 @@ trait Trait {} impl<'a> Trait for &'a str {} fn h(_: &dyn Trait) {} -#[warn(clippy::needless_borrow)] -#[allow(dead_code)] -fn issue_1432() { - let mut v = Vec::<String>::new(); - let _ = v.iter_mut().filter(|&ref a| a.is_empty()); - let _ = v.iter().filter(|&a| a.is_empty()); - - let _ = v.iter().filter(|&a| a.is_empty()); -} - -#[allow(dead_code)] -#[warn(clippy::needless_borrow)] -#[derive(Debug)] -enum Foo<'a> { - Str(&'a str), -} diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs index 1e281316c8a..059dc8ceac3 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.rs +++ b/src/tools/clippy/tests/ui/needless_borrow.rs @@ -18,7 +18,6 @@ fn main() { let vec = Vec::new(); let vec_val = g(&vec); // should not error, because `&Vec<T>` derefs to `&[T]` h(&"foo"); // should not error, because the `&&str` is required, due to `&Trait` - if let Some(ref cake) = Some(&5) {} let garbl = match 42 { 44 => &a, 45 => { @@ -43,19 +42,3 @@ trait Trait {} impl<'a> Trait for &'a str {} fn h(_: &dyn Trait) {} -#[warn(clippy::needless_borrow)] -#[allow(dead_code)] -fn issue_1432() { - let mut v = Vec::<String>::new(); - let _ = v.iter_mut().filter(|&ref a| a.is_empty()); - let _ = v.iter().filter(|&ref a| a.is_empty()); - - let _ = v.iter().filter(|&a| a.is_empty()); -} - -#[allow(dead_code)] -#[warn(clippy::needless_borrow)] -#[derive(Debug)] -enum Foo<'a> { - Str(&'a str), -} diff --git a/src/tools/clippy/tests/ui/needless_borrow.stderr b/src/tools/clippy/tests/ui/needless_borrow.stderr index bea4b41b803..6eddf26db06 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.stderr +++ b/src/tools/clippy/tests/ui/needless_borrow.stderr @@ -6,23 +6,11 @@ LL | let c = x(&&a); | = note: `-D clippy::needless-borrow` implied by `-D warnings` -error: this pattern creates a reference to a reference - --> $DIR/needless_borrow.rs:21:17 - | -LL | if let Some(ref cake) = Some(&5) {} - | ^^^^^^^^ help: change this to: `cake` - error: this expression borrows a reference (`&i32`) that is immediately dereferenced by the compiler - --> $DIR/needless_borrow.rs:28:15 + --> $DIR/needless_borrow.rs:27:15 | LL | 46 => &&a, | ^^^ help: change this to: `&a` -error: this pattern creates a reference to a reference - --> $DIR/needless_borrow.rs:51:31 - | -LL | let _ = v.iter().filter(|&ref a| a.is_empty()); - | ^^^^^ help: change this to: `a` - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.rs b/src/tools/clippy/tests/ui/needless_borrow_pat.rs new file mode 100644 index 00000000000..f0926220755 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_borrow_pat.rs @@ -0,0 +1,151 @@ +// edition:2018 +// FIXME: run-rustfix waiting on multi-span suggestions + +#![warn(clippy::needless_borrow)] +#![allow(clippy::needless_borrowed_reference)] + +fn f1(_: &str) {} +macro_rules! m1 { + ($e:expr) => { + f1($e); + }; +} +macro_rules! m3 { + ($i:ident) => { + Some(ref $i) + }; +} +macro_rules! if_chain { + (if $e:expr; $($rest:tt)*) => { + if $e { + if_chain!($($rest)*) + } + }; + + (if let $p:pat = $e:expr; $($rest:tt)*) => { + if let $p = $e { + if_chain!($($rest)*) + } + }; + + (then $b:block) => { + $b + }; +} + +#[allow(dead_code)] +fn main() { + let x = String::new(); + + // Ok, reference to a String. + let _: &String = match Some(x.clone()) { + Some(ref x) => x, + None => return, + }; + + // Ok, reference to a &mut String + let _: &&mut String = match Some(&mut x.clone()) { + Some(ref x) => x, + None => return, + }; + + // Ok, the pattern is from a macro + let _: &String = match Some(&x) { + m3!(x) => x, + None => return, + }; + + // Err, reference to a &String + let _: &String = match Some(&x) { + Some(ref x) => x, + None => return, + }; + + // Err, reference to a &String. + let _: &String = match Some(&x) { + Some(ref x) => *x, + None => return, + }; + + // Err, reference to a &String + let _: &String = match Some(&x) { + Some(ref x) => { + f1(x); + f1(*x); + x + }, + None => return, + }; + + // Err, reference to a &String + match Some(&x) { + Some(ref x) => m1!(x), + None => return, + }; + + // Err, reference to a &String + let _ = |&ref x: &&String| { + let _: &String = x; + }; + + // Err, reference to a &String + let (ref y,) = (&x,); + let _: &String = *y; + + let y = &&x; + // Ok, different y + let _: &String = *y; + + let x = (0, 0); + // Err, reference to a &u32. Don't suggest adding a reference to the field access. + let _: u32 = match Some(&x) { + Some(ref x) => x.0, + None => return, + }; + + enum E { + A(&'static u32), + B(&'static u32), + } + // Err, reference to &u32. + let _: &u32 = match E::A(&0) { + E::A(ref x) | E::B(ref x) => *x, + }; + + // Err, reference to &String. + if_chain! { + if true; + if let Some(ref x) = Some(&String::new()); + then { + f1(x); + } + } +} + +// Err, reference to a &String +fn f2<'a>(&ref x: &&'a String) -> &'a String { + let _: &String = x; + *x +} + +trait T1 { + // Err, reference to a &String + fn f(&ref x: &&String) { + let _: &String = x; + } +} + +struct S; +impl T1 for S { + // Err, reference to a &String + fn f(&ref x: &&String) { + let _: &String = *x; + } +} + +// Ok - used to error due to rustc bug +#[allow(dead_code)] +#[derive(Debug)] +enum Foo<'a> { + Str(&'a str), +} diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.stderr b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr new file mode 100644 index 00000000000..32913d59f7a --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_borrow_pat.stderr @@ -0,0 +1,112 @@ +error: this pattern creates a reference to a reference + --> $DIR/needless_borrow_pat.rs:60:14 + | +LL | Some(ref x) => x, + | ^^^^^ help: try this: `x` + | + = note: `-D clippy::needless-borrow` implied by `-D warnings` + +error: this pattern creates a reference to a reference + --> $DIR/needless_borrow_pat.rs:66:14 + | +LL | Some(ref x) => *x, + | ^^^^^ + | +help: try this + | +LL | Some(x) => x, + | ^ ^ + +error: this pattern creates a reference to a reference + --> $DIR/needless_borrow_pat.rs:72:14 + | +LL | Some(ref x) => { + | ^^^^^ + | +help: try this + | +LL | Some(x) => { +LL | f1(x); +LL | f1(x); + | + +error: this pattern creates a reference to a reference + --> $DIR/needless_borrow_pat.rs:82:14 + | +LL | Some(ref x) => m1!(x), + | ^^^^^ help: try this: `x` + +error: this pattern creates a reference to a reference + --> $DIR/needless_borrow_pat.rs:87:15 + | +LL | let _ = |&ref x: &&String| { + | ^^^^^ help: try this: `x` + +error: this pattern creates a reference to a reference + --> $DIR/needless_borrow_pat.rs:92:10 + | +LL | let (ref y,) = (&x,); + | ^^^^^ + | +help: try this + | +LL | let (y,) = (&x,); +LL | let _: &String = y; + | + +error: this pattern creates a reference to a reference + --> $DIR/needless_borrow_pat.rs:102:14 + | +LL | Some(ref x) => x.0, + | ^^^^^ help: try this: `x` + +error: this pattern creates a reference to a reference + --> $DIR/needless_borrow_pat.rs:112:14 + | +LL | E::A(ref x) | E::B(ref x) => *x, + | ^^^^^ ^^^^^ + | +help: try this + | +LL | E::A(x) | E::B(x) => x, + | ^ ^ ^ + +error: this pattern creates a reference to a reference + --> $DIR/needless_borrow_pat.rs:118:21 + | +LL | if let Some(ref x) = Some(&String::new()); + | ^^^^^ help: try this: `x` + +error: this pattern creates a reference to a reference + --> $DIR/needless_borrow_pat.rs:126:12 + | +LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { + | ^^^^^ + | +help: try this + | +LL | fn f2<'a>(&x: &&'a String) -> &'a String { +LL | let _: &String = x; +LL | x + | + +error: this pattern creates a reference to a reference + --> $DIR/needless_borrow_pat.rs:133:11 + | +LL | fn f(&ref x: &&String) { + | ^^^^^ help: try this: `x` + +error: this pattern creates a reference to a reference + --> $DIR/needless_borrow_pat.rs:141:11 + | +LL | fn f(&ref x: &&String) { + | ^^^^^ + | +help: try this + | +LL | fn f(&x: &&String) { +LL | let _: &String = x; + | + +error: aborting due to 12 previous errors + diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed index af6c7bf15ea..6ecbbcb6249 100644 --- a/src/tools/clippy/tests/ui/needless_collect.fixed +++ b/src/tools/clippy/tests/ui/needless_collect.fixed @@ -2,7 +2,7 @@ #![allow(unused, clippy::suspicious_map, clippy::iter_count)] -use std::collections::{BTreeSet, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList}; #[warn(clippy::needless_collect)] #[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)] @@ -13,9 +13,24 @@ fn main() { // Empty } sample.iter().cloned().any(|x| x == 1); - sample.iter().map(|x| (x, x)).count(); + // #7164 HashMap's and BTreeMap's `len` usage should not be linted + sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len(); + sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().len(); + + sample.iter().map(|x| (x, x)).next().is_none(); + sample.iter().map(|x| (x, x)).next().is_none(); + // Notice the `HashSet`--this should not be linted sample.iter().collect::<HashSet<_>>().len(); // Neither should this sample.iter().collect::<BTreeSet<_>>().len(); + + sample.iter().count(); + sample.iter().next().is_none(); + sample.iter().cloned().any(|x| x == 1); + sample.iter().any(|x| x == &1); + + // `BinaryHeap` doesn't have `contains` method + sample.iter().count(); + sample.iter().next().is_none(); } diff --git a/src/tools/clippy/tests/ui/needless_collect.rs b/src/tools/clippy/tests/ui/needless_collect.rs index 6ae14f370b1..8dc69bcf5b3 100644 --- a/src/tools/clippy/tests/ui/needless_collect.rs +++ b/src/tools/clippy/tests/ui/needless_collect.rs @@ -2,7 +2,7 @@ #![allow(unused, clippy::suspicious_map, clippy::iter_count)] -use std::collections::{BTreeSet, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap, HashSet, LinkedList}; #[warn(clippy::needless_collect)] #[allow(unused_variables, clippy::iter_cloned_collect, clippy::iter_next_slice)] @@ -13,9 +13,24 @@ fn main() { // Empty } sample.iter().cloned().collect::<Vec<_>>().contains(&1); + // #7164 HashMap's and BTreeMap's `len` usage should not be linted sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len(); + sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().len(); + + sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().is_empty(); + sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().is_empty(); + // Notice the `HashSet`--this should not be linted sample.iter().collect::<HashSet<_>>().len(); // Neither should this sample.iter().collect::<BTreeSet<_>>().len(); + + sample.iter().collect::<LinkedList<_>>().len(); + sample.iter().collect::<LinkedList<_>>().is_empty(); + sample.iter().cloned().collect::<LinkedList<_>>().contains(&1); + sample.iter().collect::<LinkedList<_>>().contains(&&1); + + // `BinaryHeap` doesn't have `contains` method + sample.iter().collect::<BinaryHeap<_>>().len(); + sample.iter().collect::<BinaryHeap<_>>().is_empty(); } diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr index 2a9539d5975..039091627a8 100644 --- a/src/tools/clippy/tests/ui/needless_collect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect.stderr @@ -19,10 +19,52 @@ LL | sample.iter().cloned().collect::<Vec<_>>().contains(&1); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)` error: avoid using `collect()` when not needed - --> $DIR/needless_collect.rs:16:35 + --> $DIR/needless_collect.rs:20:35 | -LL | sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().len(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` +LL | sample.iter().map(|x| (x, x)).collect::<HashMap<_, _>>().is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` -error: aborting due to 4 previous errors +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:21:35 + | +LL | sample.iter().map(|x| (x, x)).collect::<BTreeMap<_, _>>().is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:28:19 + | +LL | sample.iter().collect::<LinkedList<_>>().len(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:29:19 + | +LL | sample.iter().collect::<LinkedList<_>>().is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:30:28 + | +LL | sample.iter().cloned().collect::<LinkedList<_>>().contains(&1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == 1)` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:31:19 + | +LL | sample.iter().collect::<LinkedList<_>>().contains(&&1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &1)` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:34:19 + | +LL | sample.iter().collect::<BinaryHeap<_>>().len(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `count()` + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:35:19 + | +LL | sample.iter().collect::<BinaryHeap<_>>().is_empty(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `next().is_none()` + +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/needless_collect_indirect.rs b/src/tools/clippy/tests/ui/needless_collect_indirect.rs index 2458bf1e490..2c94235b8f5 100644 --- a/src/tools/clippy/tests/ui/needless_collect_indirect.rs +++ b/src/tools/clippy/tests/ui/needless_collect_indirect.rs @@ -1,4 +1,4 @@ -use std::collections::{BinaryHeap, HashMap, LinkedList, VecDeque}; +use std::collections::{BinaryHeap, HashMap, HashSet, LinkedList, VecDeque}; fn main() { let sample = [1; 5]; @@ -75,3 +75,9 @@ mod issue7110 { buffer.len() } } + +fn allow_test() { + #[allow(clippy::needless_collect)] + let v = [1].iter().collect::<Vec<_>>(); + v.into_iter().collect::<HashSet<_>>(); +} diff --git a/src/tools/clippy/tests/ui/needless_question_mark.fixed b/src/tools/clippy/tests/ui/needless_question_mark.fixed index 52ddd9d2dc8..f1fc81aa12b 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.fixed +++ b/src/tools/clippy/tests/ui/needless_question_mark.fixed @@ -94,6 +94,11 @@ where Ok(x?) } +// not quite needless +fn deref_ref(s: Option<&String>) -> Option<&str> { + Some(s?) +} + fn main() {} // #6921 if a macro wraps an expr in Some( ) and the ? is in the macro use, diff --git a/src/tools/clippy/tests/ui/needless_question_mark.rs b/src/tools/clippy/tests/ui/needless_question_mark.rs index 1ea4ba0d83f..44a0c5f61b5 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.rs +++ b/src/tools/clippy/tests/ui/needless_question_mark.rs @@ -94,6 +94,11 @@ where Ok(x?) } +// not quite needless +fn deref_ref(s: Option<&String>) -> Option<&str> { + Some(s?) +} + fn main() {} // #6921 if a macro wraps an expr in Some( ) and the ? is in the macro use, diff --git a/src/tools/clippy/tests/ui/needless_question_mark.stderr b/src/tools/clippy/tests/ui/needless_question_mark.stderr index f1f05d1af3a..02bf50d077a 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.stderr +++ b/src/tools/clippy/tests/ui/needless_question_mark.stderr @@ -67,7 +67,7 @@ LL | return Ok(t.magic?); | ^^^^^^^^^^^^ help: try: `t.magic` error: question mark operator is useless here - --> $DIR/needless_question_mark.rs:115:27 + --> $DIR/needless_question_mark.rs:120:27 | LL | || -> Option<_> { Some(Some($expr)?) }() | ^^^^^^^^^^^^^^^^^^ help: try: `Some($expr)` diff --git a/src/tools/clippy/tests/ui/no_effect.rs b/src/tools/clippy/tests/ui/no_effect.rs index 8fbfcb79860..7ec845adfaa 100644 --- a/src/tools/clippy/tests/ui/no_effect.rs +++ b/src/tools/clippy/tests/ui/no_effect.rs @@ -91,6 +91,9 @@ fn main() { let s: String = "foo".into(); FooString { s: s }; + #[allow(clippy::no_effect)] + 0; + // Do not warn get_number(); unsafe { unsafe_fn() }; diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed index 47e7460fa7a..769ccc14bc1 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.fixed +++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed @@ -10,7 +10,11 @@ fn bad1(string: Option<&str>) -> (bool, &str) { fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> { if string.is_none() { None - } else { string.map_or(Some((false, "")), |x| Some((true, x))) } + } else if let Some(x) = string { + Some((true, x)) + } else { + Some((false, "")) + } } fn unop_bad(string: &Option<&str>, mut num: Option<i32>) { diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr index 7aab068800a..4ebb068d22e 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.stderr +++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr @@ -11,17 +11,6 @@ LL | | } = note: `-D clippy::option-if-let-else` implied by `-D warnings` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:17:12 - | -LL | } else if let Some(x) = string { - | ____________^ -LL | | Some((true, x)) -LL | | } else { -LL | | Some((false, "")) -LL | | } - | |_____^ help: try: `{ string.map_or(Some((false, "")), |x| Some((true, x))) }` - -error: use Option::map_or instead of an if let/else --> $DIR/option_if_let_else.rs:25:13 | LL | let _ = if let Some(s) = *string { s.len() } else { 0 }; @@ -159,5 +148,5 @@ error: use Option::map_or instead of an if let/else LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs new file mode 100644 index 00000000000..c7235e1c221 --- /dev/null +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs @@ -0,0 +1,76 @@ +// edition:2018 +// FIXME: run-rustfix waiting on multi-span suggestions + +#![warn(clippy::ref_binding_to_reference)] +#![allow(clippy::needless_borrowed_reference)] + +fn f1(_: &str) {} +macro_rules! m2 { + ($e:expr) => { + f1(*$e); + }; +} +macro_rules! m3 { + ($i:ident) => { + Some(ref $i) + }; +} + +#[allow(dead_code)] +fn main() { + let x = String::new(); + + // Ok, the pattern is from a macro + let _: &&String = match Some(&x) { + m3!(x) => x, + None => return, + }; + + // Err, reference to a &String + let _: &&String = match Some(&x) { + Some(ref x) => x, + None => return, + }; + + // Err, reference to a &String + let _: &&String = match Some(&x) { + Some(ref x) => { + f1(x); + f1(*x); + x + }, + None => return, + }; + + // Err, reference to a &String + match Some(&x) { + Some(ref x) => m2!(x), + None => return, + } + + // Err, reference to a &String + let _ = |&ref x: &&String| { + let _: &&String = x; + }; +} + +// Err, reference to a &String +fn f2<'a>(&ref x: &&'a String) -> &'a String { + let _: &&String = x; + *x +} + +trait T1 { + // Err, reference to a &String + fn f(&ref x: &&String) { + let _: &&String = x; + } +} + +struct S; +impl T1 for S { + // Err, reference to a &String + fn f(&ref x: &&String) { + let _: &&String = x; + } +} diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr new file mode 100644 index 00000000000..00aeff4fefa --- /dev/null +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.stderr @@ -0,0 +1,88 @@ +error: this pattern creates a reference to a reference + --> $DIR/ref_binding_to_reference.rs:31:14 + | +LL | Some(ref x) => x, + | ^^^^^ + | + = note: `-D clippy::ref-binding-to-reference` implied by `-D warnings` +help: try this + | +LL | Some(x) => &x, + | ^ ^^ + +error: this pattern creates a reference to a reference + --> $DIR/ref_binding_to_reference.rs:37:14 + | +LL | Some(ref x) => { + | ^^^^^ + | +help: try this + | +LL | Some(x) => { +LL | f1(x); +LL | f1(x); +LL | &x + | + +error: this pattern creates a reference to a reference + --> $DIR/ref_binding_to_reference.rs:47:14 + | +LL | Some(ref x) => m2!(x), + | ^^^^^ + | +help: try this + | +LL | Some(x) => m2!(&x), + | ^ ^^ + +error: this pattern creates a reference to a reference + --> $DIR/ref_binding_to_reference.rs:52:15 + | +LL | let _ = |&ref x: &&String| { + | ^^^^^ + | +help: try this + | +LL | let _ = |&x: &&String| { +LL | let _: &&String = &x; + | + +error: this pattern creates a reference to a reference + --> $DIR/ref_binding_to_reference.rs:58:12 + | +LL | fn f2<'a>(&ref x: &&'a String) -> &'a String { + | ^^^^^ + | +help: try this + | +LL | fn f2<'a>(&x: &&'a String) -> &'a String { +LL | let _: &&String = &x; +LL | x + | + +error: this pattern creates a reference to a reference + --> $DIR/ref_binding_to_reference.rs:65:11 + | +LL | fn f(&ref x: &&String) { + | ^^^^^ + | +help: try this + | +LL | fn f(&x: &&String) { +LL | let _: &&String = &x; + | + +error: this pattern creates a reference to a reference + --> $DIR/ref_binding_to_reference.rs:73:11 + | +LL | fn f(&ref x: &&String) { + | ^^^^^ + | +help: try this + | +LL | fn f(&x: &&String) { +LL | let _: &&String = &x; + | + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui/similar_names.rs b/src/tools/clippy/tests/ui/similar_names.rs index 5981980988b..2b1bc1f4859 100644 --- a/src/tools/clippy/tests/ui/similar_names.rs +++ b/src/tools/clippy/tests/ui/similar_names.rs @@ -72,6 +72,10 @@ fn main() { let rx1: i32; let tx_cake: i32; let rx_cake: i32; + + // names often used in win32 code (for example WindowProc) + let wparam: i32; + let lparam: i32; } fn foo() { diff --git a/src/tools/clippy/tests/ui/similar_names.stderr b/src/tools/clippy/tests/ui/similar_names.stderr index 0256f126a94..a7eb2be0778 100644 --- a/src/tools/clippy/tests/ui/similar_names.stderr +++ b/src/tools/clippy/tests/ui/similar_names.stderr @@ -92,13 +92,13 @@ LL | let parsee: i32; | ^^^^^^ error: binding's name is too similar to existing binding - --> $DIR/similar_names.rs:81:16 + --> $DIR/similar_names.rs:85:16 | LL | bpple: sprang, | ^^^^^^ | note: existing binding defined here - --> $DIR/similar_names.rs:80:16 + --> $DIR/similar_names.rs:84:16 | LL | apple: spring, | ^^^^^^ diff --git a/src/tools/clippy/tests/ui/single_char_pattern.fixed b/src/tools/clippy/tests/ui/single_char_pattern.fixed index fcbe9af9f56..1abd2b7883d 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.fixed +++ b/src/tools/clippy/tests/ui/single_char_pattern.fixed @@ -25,8 +25,8 @@ fn main() { x.rsplit('x'); x.split_terminator('x'); x.rsplit_terminator('x'); - x.splitn(0, 'x'); - x.rsplitn(0, 'x'); + x.splitn(2, 'x'); + x.rsplitn(2, 'x'); x.matches('x'); x.rmatches('x'); x.match_indices('x'); diff --git a/src/tools/clippy/tests/ui/single_char_pattern.rs b/src/tools/clippy/tests/ui/single_char_pattern.rs index b8bc20f4070..e662bf34be2 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.rs +++ b/src/tools/clippy/tests/ui/single_char_pattern.rs @@ -25,8 +25,8 @@ fn main() { x.rsplit("x"); x.split_terminator("x"); x.rsplit_terminator("x"); - x.splitn(0, "x"); - x.rsplitn(0, "x"); + x.splitn(2, "x"); + x.rsplitn(2, "x"); x.matches("x"); x.rmatches("x"); x.match_indices("x"); diff --git a/src/tools/clippy/tests/ui/single_char_pattern.stderr b/src/tools/clippy/tests/ui/single_char_pattern.stderr index 6d94d8a34e3..22d4b2d460f 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.stderr +++ b/src/tools/clippy/tests/ui/single_char_pattern.stderr @@ -75,13 +75,13 @@ LL | x.rsplit_terminator("x"); error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:28:17 | -LL | x.splitn(0, "x"); +LL | x.splitn(2, "x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern --> $DIR/single_char_pattern.rs:29:18 | -LL | x.rsplitn(0, "x"); +LL | x.rsplitn(2, "x"); | ^^^ help: try using a `char` instead: `'x'` error: single-character string constant used as pattern diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.rs b/src/tools/clippy/tests/ui/suspicious_splitn.rs new file mode 100644 index 00000000000..a21d94cf20b --- /dev/null +++ b/src/tools/clippy/tests/ui/suspicious_splitn.rs @@ -0,0 +1,20 @@ +#![warn(clippy::suspicious_splitn)] + +fn main() { + let _ = "a,b,c".splitn(3, ','); + let _ = [0, 1, 2, 1, 3].splitn(3, |&x| x == 1); + let _ = "".splitn(0, ','); + let _ = [].splitn(0, |&x: &u32| x == 1); + + let _ = "a,b".splitn(0, ','); + let _ = "a,b".rsplitn(0, ','); + let _ = "a,b".splitn(1, ','); + let _ = [0, 1, 2].splitn(0, |&x| x == 1); + let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1); + let _ = [0, 1, 2].splitn(1, |&x| x == 1); + let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1); + + const X: usize = 0; + let _ = "a,b".splitn(X + 1, ','); + let _ = "a,b".splitn(X, ','); +} diff --git a/src/tools/clippy/tests/ui/suspicious_splitn.stderr b/src/tools/clippy/tests/ui/suspicious_splitn.stderr new file mode 100644 index 00000000000..b6220ae2393 --- /dev/null +++ b/src/tools/clippy/tests/ui/suspicious_splitn.stderr @@ -0,0 +1,75 @@ +error: `splitn` called with `0` splits + --> $DIR/suspicious_splitn.rs:9:13 + | +LL | let _ = "a,b".splitn(0, ','); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::suspicious-splitn` implied by `-D warnings` + = note: the resulting iterator will always return `None` + +error: `rsplitn` called with `0` splits + --> $DIR/suspicious_splitn.rs:10:13 + | +LL | let _ = "a,b".rsplitn(0, ','); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return `None` + +error: `splitn` called with `1` split + --> $DIR/suspicious_splitn.rs:11:13 + | +LL | let _ = "a,b".splitn(1, ','); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return the entire string followed by `None` + +error: `splitn` called with `0` splits + --> $DIR/suspicious_splitn.rs:12:13 + | +LL | let _ = [0, 1, 2].splitn(0, |&x| x == 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return `None` + +error: `splitn_mut` called with `0` splits + --> $DIR/suspicious_splitn.rs:13:13 + | +LL | let _ = [0, 1, 2].splitn_mut(0, |&x| x == 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return `None` + +error: `splitn` called with `1` split + --> $DIR/suspicious_splitn.rs:14:13 + | +LL | let _ = [0, 1, 2].splitn(1, |&x| x == 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return the entire slice followed by `None` + +error: `rsplitn_mut` called with `1` split + --> $DIR/suspicious_splitn.rs:15:13 + | +LL | let _ = [0, 1, 2].rsplitn_mut(1, |&x| x == 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return the entire slice followed by `None` + +error: `splitn` called with `1` split + --> $DIR/suspicious_splitn.rs:18:13 + | +LL | let _ = "a,b".splitn(X + 1, ','); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return the entire string followed by `None` + +error: `splitn` called with `0` splits + --> $DIR/suspicious_splitn.rs:19:13 + | +LL | let _ = "a,b".splitn(X, ','); + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: the resulting iterator will always return `None` + +error: aborting due to 9 previous errors + diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr index ccc3cdb2b74..2b0005bbff1 100644 --- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr +++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.stderr @@ -89,12 +89,6 @@ LL | fn trait_method(&self, _foo: &Foo); | ^^^^ help: consider passing by value instead: `Foo` error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) - --> $DIR/trivially_copy_pass_by_ref.rs:80:37 - | -LL | fn trait_method2(&self, _color: &Color); - | ^^^^^^ help: consider passing by value instead: `Color` - -error: this argument (N byte) is passed by reference, but would be more efficient if passed by value (limit: N byte) --> $DIR/trivially_copy_pass_by_ref.rs:108:21 | LL | fn foo_never(x: &i32) { @@ -106,5 +100,5 @@ error: this argument (N byte) is passed by reference, but would be more efficien LL | fn foo(x: &i32) { | ^^^^ help: consider passing by value instead: `i32` -error: aborting due to 17 previous errors +error: aborting due to 16 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_wraps.rs b/src/tools/clippy/tests/ui/unnecessary_wraps.rs index 54f22e3ee6a..63648ef5826 100644 --- a/src/tools/clippy/tests/ui/unnecessary_wraps.rs +++ b/src/tools/clippy/tests/ui/unnecessary_wraps.rs @@ -65,7 +65,7 @@ fn func10() -> Option<()> { unimplemented!() } -struct A; +pub struct A; impl A { // should not be linted diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed index 3c422cc4fee..f0c2ba7ccdf 100644 --- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed +++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed @@ -1,10 +1,11 @@ // run-rustfix +// aux-build:proc_macro_derive.rs #![warn(clippy::unseparated_literal_suffix)] #![allow(dead_code)] #[macro_use] -extern crate clippy_mini_macro_test; +extern crate proc_macro_derive; // Test for proc-macro attribute #[derive(ClippyMiniMacroTest)] diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs index 09608661e0e..f44880b4147 100644 --- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs +++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs @@ -1,10 +1,11 @@ // run-rustfix +// aux-build:proc_macro_derive.rs #![warn(clippy::unseparated_literal_suffix)] #![allow(dead_code)] #[macro_use] -extern crate clippy_mini_macro_test; +extern crate proc_macro_derive; // Test for proc-macro attribute #[derive(ClippyMiniMacroTest)] diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr index a0c0be7a9d1..ab2f75e0c56 100644 --- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr +++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.stderr @@ -1,5 +1,5 @@ error: integer type suffix should be separated by an underscore - --> $DIR/unseparated_prefix_literals.rs:23:18 + --> $DIR/unseparated_prefix_literals.rs:24:18 | LL | let _fail1 = 1234i32; | ^^^^^^^ help: add an underscore: `1234_i32` @@ -7,43 +7,43 @@ LL | let _fail1 = 1234i32; = note: `-D clippy::unseparated-literal-suffix` implied by `-D warnings` error: integer type suffix should be separated by an underscore - --> $DIR/unseparated_prefix_literals.rs:24:18 + --> $DIR/unseparated_prefix_literals.rs:25:18 | LL | let _fail2 = 1234u32; | ^^^^^^^ help: add an underscore: `1234_u32` error: integer type suffix should be separated by an underscore - --> $DIR/unseparated_prefix_literals.rs:25:18 + --> $DIR/unseparated_prefix_literals.rs:26:18 | LL | let _fail3 = 1234isize; | ^^^^^^^^^ help: add an underscore: `1234_isize` error: integer type suffix should be separated by an underscore - --> $DIR/unseparated_prefix_literals.rs:26:18 + --> $DIR/unseparated_prefix_literals.rs:27:18 | LL | let _fail4 = 1234usize; | ^^^^^^^^^ help: add an underscore: `1234_usize` error: integer type suffix should be separated by an underscore - --> $DIR/unseparated_prefix_literals.rs:27:18 + --> $DIR/unseparated_prefix_literals.rs:28:18 | LL | let _fail5 = 0x123isize; | ^^^^^^^^^^ help: add an underscore: `0x123_isize` error: float type suffix should be separated by an underscore - --> $DIR/unseparated_prefix_literals.rs:31:19 + --> $DIR/unseparated_prefix_literals.rs:32:19 | LL | let _failf1 = 1.5f32; | ^^^^^^ help: add an underscore: `1.5_f32` error: float type suffix should be separated by an underscore - --> $DIR/unseparated_prefix_literals.rs:32:19 + --> $DIR/unseparated_prefix_literals.rs:33:19 | LL | let _failf2 = 1f32; | ^^^^ help: add an underscore: `1_f32` error: integer type suffix should be separated by an underscore - --> $DIR/unseparated_prefix_literals.rs:15:9 + --> $DIR/unseparated_prefix_literals.rs:16:9 | LL | 42usize | ^^^^^^^ help: add an underscore: `42_usize` @@ -54,7 +54,7 @@ LL | let _ = lit_from_macro!(); = note: this error originates in the macro `lit_from_macro` (in Nightly builds, run with -Z macro-backtrace for more info) error: integer type suffix should be separated by an underscore - --> $DIR/unseparated_prefix_literals.rs:40:16 + --> $DIR/unseparated_prefix_literals.rs:41:16 | LL | assert_eq!(4897u32, 32223); | ^^^^^^^ help: add an underscore: `4897_u32` diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs new file mode 100644 index 00000000000..4f4203f5fdb --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_async.rs @@ -0,0 +1,15 @@ +// edition:2018 +#![warn(clippy::unused_async)] + +async fn foo() -> i32 { + 4 +} + +async fn bar() -> i32 { + foo().await +} + +fn main() { + foo(); + bar(); +} diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr new file mode 100644 index 00000000000..8b834d205b1 --- /dev/null +++ b/src/tools/clippy/tests/ui/unused_async.stderr @@ -0,0 +1,13 @@ +error: unused `async` for function with no await statements + --> $DIR/unused_async.rs:4:1 + | +LL | / async fn foo() -> i32 { +LL | | 4 +LL | | } + | |_^ + | + = note: `-D clippy::unused-async` implied by `-D warnings` + = help: consider removing the `async` from this function + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed index 1282befdfb3..631da6fe066 100644 --- a/src/tools/clippy/tests/ui/use_self.fixed +++ b/src/tools/clippy/tests/ui/use_self.fixed @@ -462,3 +462,33 @@ mod issue6818 { a: i32, } } + +mod issue7206 { + struct MyStruct<const C: char>; + impl From<MyStruct<'a'>> for MyStruct<'b'> { + fn from(_s: MyStruct<'a'>) -> Self { + Self + } + } + + // keep linting non-`Const` generic args + struct S<'a> { + inner: &'a str, + } + + struct S2<T> { + inner: T, + } + + impl<T> S2<T> { + fn new() -> Self { + unimplemented!(); + } + } + + impl<'a> S2<S<'a>> { + fn new_again() -> Self { + Self::new() + } + } +} diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs index 7aaac7b2414..7a10d755faa 100644 --- a/src/tools/clippy/tests/ui/use_self.rs +++ b/src/tools/clippy/tests/ui/use_self.rs @@ -462,3 +462,33 @@ mod issue6818 { a: i32, } } + +mod issue7206 { + struct MyStruct<const C: char>; + impl From<MyStruct<'a'>> for MyStruct<'b'> { + fn from(_s: MyStruct<'a'>) -> Self { + Self + } + } + + // keep linting non-`Const` generic args + struct S<'a> { + inner: &'a str, + } + + struct S2<T> { + inner: T, + } + + impl<T> S2<T> { + fn new() -> Self { + unimplemented!(); + } + } + + impl<'a> S2<S<'a>> { + fn new_again() -> Self { + S2::new() + } + } +} diff --git a/src/tools/clippy/tests/ui/use_self.stderr b/src/tools/clippy/tests/ui/use_self.stderr index a32a9b9157d..cf6222c9b45 100644 --- a/src/tools/clippy/tests/ui/use_self.stderr +++ b/src/tools/clippy/tests/ui/use_self.stderr @@ -162,5 +162,11 @@ error: unnecessary structure name repetition LL | A::new::<submod::B>(submod::B {}) | ^ help: use the applicable keyword: `Self` -error: aborting due to 27 previous errors +error: unnecessary structure name repetition + --> $DIR/use_self.rs:491:13 + | +LL | S2::new() + | ^^ help: use the applicable keyword: `Self` + +error: aborting due to 28 previous errors diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index 03977de9455..76aa82068d6 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -70,4 +70,23 @@ fn main() { let a: i32 = 1; let b: i32 = 1; let _ = (a + b) * 3; + + // see #7205 + let s: Foo<'a'> = Foo; + let _: Foo<'b'> = s.into(); + let s2: Foo<'a'> = Foo; + let _: Foo<'a'> = s2; + let s3: Foo<'a'> = Foo; + let _ = s3; + let s4: Foo<'a'> = Foo; + let _ = vec![s4, s4, s4].into_iter(); +} + +#[derive(Copy, Clone)] +struct Foo<const C: char>; + +impl From<Foo<'a'>> for Foo<'b'> { + fn from(_s: Foo<'a'>) -> Self { + Foo + } } diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index f6e094c1661..ccee7abb404 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -70,4 +70,23 @@ fn main() { let a: i32 = 1; let b: i32 = 1; let _ = i32::from(a + b) * 3; + + // see #7205 + let s: Foo<'a'> = Foo; + let _: Foo<'b'> = s.into(); + let s2: Foo<'a'> = Foo; + let _: Foo<'a'> = s2.into(); + let s3: Foo<'a'> = Foo; + let _ = Foo::<'a'>::from(s3); + let s4: Foo<'a'> = Foo; + let _ = vec![s4, s4, s4].into_iter().into_iter(); +} + +#[derive(Copy, Clone)] +struct Foo<const C: char>; + +impl From<Foo<'a'>> for Foo<'b'> { + fn from(_s: Foo<'a'>) -> Self { + Foo + } } diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr index 26a33595031..e6760f700f3 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion.stderr @@ -70,5 +70,23 @@ error: useless conversion to the same type: `i32` LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` -error: aborting due to 11 previous errors +error: useless conversion to the same type: `Foo<'a'>` + --> $DIR/useless_conversion.rs:78:23 + | +LL | let _: Foo<'a'> = s2.into(); + | ^^^^^^^^^ help: consider removing `.into()`: `s2` + +error: useless conversion to the same type: `Foo<'a'>` + --> $DIR/useless_conversion.rs:80:13 + | +LL | let _ = Foo::<'a'>::from(s3); + | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3` + +error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>` + --> $DIR/useless_conversion.rs:82:13 + | +LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` + +error: aborting due to 14 previous errors diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed index 749393db124..c3e2cf0c4a4 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::while_let_on_iterator)] -#![allow(clippy::never_loop, unreachable_code, unused_mut)] +#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)] fn base() { let mut iter = 1..20; @@ -41,13 +41,6 @@ fn base() { // or this let mut iter = 1u32..20; while let Some(_) = iter.next() { - break; - } - println!("Remaining iter {:?}", iter); - - // or this - let mut iter = 1u32..20; - while let Some(_) = iter.next() { iter = 1..20; } } @@ -135,18 +128,6 @@ fn refutable2() { fn nested_loops() { let a = [42, 1337]; - let mut y = a.iter(); - loop { - // x is reused, so don't lint here - while let Some(_) = y.next() {} - } - - let mut y = a.iter(); - for _ in 0..2 { - while let Some(_) = y.next() { - // y is reused, don't lint - } - } loop { let mut y = a.iter(); @@ -167,10 +148,8 @@ fn issue1121() { } fn issue2965() { - // This should not cause an ICE and suggest: - // - // for _ in values.iter() {} - // + // This should not cause an ICE + use std::collections::HashSet; let mut values = HashSet::new(); values.insert(1); @@ -205,13 +184,145 @@ fn issue1654() { } } +fn issue6491() { + // Used in outer loop, needs &mut + let mut it = 1..40; + while let Some(n) = it.next() { + for m in &mut it { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + println!("n still is {}", n); + } + + // This is fine, inner loop uses a new iterator. + let mut it = 1..40; + for n in it { + let mut it = 1..40; + for m in it { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + + // Weird binding shouldn't change anything. + let (mut it, _) = (1..40, 0); + for m in it { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + + // Used after the loop, needs &mut. + let mut it = 1..40; + for m in &mut it { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + println!("next item {}", it.next().unwrap()); + + println!("n still is {}", n); + } +} + +fn issue6231() { + // Closure in the outer loop, needs &mut + let mut it = 1..40; + let mut opt = Some(0); + while let Some(n) = opt.take().or_else(|| it.next()) { + for m in &mut it { + if n % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + println!("n still is {}", n); + } +} + +fn issue1924() { + struct S<T>(T); + impl<T: Iterator<Item = u32>> S<T> { + fn f(&mut self) -> Option<u32> { + // Used as a field. + for i in &mut self.0 { + if !(3..=7).contains(&i) { + return Some(i); + } + } + None + } + + fn f2(&mut self) -> Option<u32> { + // Don't lint, self borrowed inside the loop + while let Some(i) = self.0.next() { + if i == 1 { + return self.f(); + } + } + None + } + } + impl<T: Iterator<Item = u32>> S<(S<T>, Option<u32>)> { + fn f3(&mut self) -> Option<u32> { + // Don't lint, self borrowed inside the loop + while let Some(i) = self.0.0.0.next() { + if i == 1 { + return self.0.0.f(); + } + } + while let Some(i) = self.0.0.0.next() { + if i == 1 { + return self.f3(); + } + } + // This one is fine, a different field is borrowed + for i in &mut self.0.0.0 { + if i == 1 { + return self.0.1.take(); + } else { + self.0.1 = Some(i); + } + } + None + } + } + + struct S2<T>(T, u32); + impl<T: Iterator<Item = u32>> Iterator for S2<T> { + type Item = u32; + fn next(&mut self) -> Option<u32> { + self.0.next() + } + } + + // Don't lint, field of the iterator is accessed in the loop + let mut it = S2(1..40, 0); + while let Some(n) = it.next() { + if n == it.1 { + break; + } + } + + // Needs &mut, field of the iterator is accessed after the loop + let mut it = S2(1..40, 0); + for n in &mut it { + if n == 0 { + break; + } + } + println!("iterator field {}", it.1); +} + fn main() { - base(); - refutable(); - refutable2(); - nested_loops(); - issue1121(); - issue2965(); - issue3670(); - issue1654(); + let mut it = 0..20; + for _ in it { + println!("test"); + } } diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs index 30e3b82a7cc..1717006a449 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs @@ -1,7 +1,7 @@ // run-rustfix #![warn(clippy::while_let_on_iterator)] -#![allow(clippy::never_loop, unreachable_code, unused_mut)] +#![allow(clippy::never_loop, unreachable_code, unused_mut, dead_code)] fn base() { let mut iter = 1..20; @@ -41,13 +41,6 @@ fn base() { // or this let mut iter = 1u32..20; while let Some(_) = iter.next() { - break; - } - println!("Remaining iter {:?}", iter); - - // or this - let mut iter = 1u32..20; - while let Some(_) = iter.next() { iter = 1..20; } } @@ -135,18 +128,6 @@ fn refutable2() { fn nested_loops() { let a = [42, 1337]; - let mut y = a.iter(); - loop { - // x is reused, so don't lint here - while let Some(_) = y.next() {} - } - - let mut y = a.iter(); - for _ in 0..2 { - while let Some(_) = y.next() { - // y is reused, don't lint - } - } loop { let mut y = a.iter(); @@ -167,10 +148,8 @@ fn issue1121() { } fn issue2965() { - // This should not cause an ICE and suggest: - // - // for _ in values.iter() {} - // + // This should not cause an ICE + use std::collections::HashSet; let mut values = HashSet::new(); values.insert(1); @@ -205,13 +184,145 @@ fn issue1654() { } } +fn issue6491() { + // Used in outer loop, needs &mut + let mut it = 1..40; + while let Some(n) = it.next() { + while let Some(m) = it.next() { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + println!("n still is {}", n); + } + + // This is fine, inner loop uses a new iterator. + let mut it = 1..40; + while let Some(n) = it.next() { + let mut it = 1..40; + while let Some(m) = it.next() { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + + // Weird binding shouldn't change anything. + let (mut it, _) = (1..40, 0); + while let Some(m) = it.next() { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + + // Used after the loop, needs &mut. + let mut it = 1..40; + while let Some(m) = it.next() { + if m % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + println!("next item {}", it.next().unwrap()); + + println!("n still is {}", n); + } +} + +fn issue6231() { + // Closure in the outer loop, needs &mut + let mut it = 1..40; + let mut opt = Some(0); + while let Some(n) = opt.take().or_else(|| it.next()) { + while let Some(m) = it.next() { + if n % 10 == 0 { + break; + } + println!("doing something with m: {}", m); + } + println!("n still is {}", n); + } +} + +fn issue1924() { + struct S<T>(T); + impl<T: Iterator<Item = u32>> S<T> { + fn f(&mut self) -> Option<u32> { + // Used as a field. + while let Some(i) = self.0.next() { + if i < 3 || i > 7 { + return Some(i); + } + } + None + } + + fn f2(&mut self) -> Option<u32> { + // Don't lint, self borrowed inside the loop + while let Some(i) = self.0.next() { + if i == 1 { + return self.f(); + } + } + None + } + } + impl<T: Iterator<Item = u32>> S<(S<T>, Option<u32>)> { + fn f3(&mut self) -> Option<u32> { + // Don't lint, self borrowed inside the loop + while let Some(i) = self.0.0.0.next() { + if i == 1 { + return self.0.0.f(); + } + } + while let Some(i) = self.0.0.0.next() { + if i == 1 { + return self.f3(); + } + } + // This one is fine, a different field is borrowed + while let Some(i) = self.0.0.0.next() { + if i == 1 { + return self.0.1.take(); + } else { + self.0.1 = Some(i); + } + } + None + } + } + + struct S2<T>(T, u32); + impl<T: Iterator<Item = u32>> Iterator for S2<T> { + type Item = u32; + fn next(&mut self) -> Option<u32> { + self.0.next() + } + } + + // Don't lint, field of the iterator is accessed in the loop + let mut it = S2(1..40, 0); + while let Some(n) = it.next() { + if n == it.1 { + break; + } + } + + // Needs &mut, field of the iterator is accessed after the loop + let mut it = S2(1..40, 0); + while let Some(n) = it.next() { + if n == 0 { + break; + } + } + println!("iterator field {}", it.1); +} + fn main() { - base(); - refutable(); - refutable2(); - nested_loops(); - issue1121(); - issue2965(); - issue3670(); - issue1654(); + let mut it = 0..20; + while let Some(..) = it.next() { + println!("test"); + } } diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr index 6554977c798..eff559bef7e 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.stderr +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.stderr @@ -19,28 +19,96 @@ LL | while let Some(_) = iter.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in iter` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:101:9 + --> $DIR/while_let_on_iterator.rs:94:9 | LL | while let Some([..]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [..] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:108:9 + --> $DIR/while_let_on_iterator.rs:101:9 | LL | while let Some([_x]) = it.next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for [_x] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:121:9 + --> $DIR/while_let_on_iterator.rs:114:9 | LL | while let Some(x @ [_]) = it.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for x @ [_] in it` error: this loop could be written as a `for` loop - --> $DIR/while_let_on_iterator.rs:153:9 + --> $DIR/while_let_on_iterator.rs:134:9 | LL | while let Some(_) = y.next() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in y` -error: aborting due to 7 previous errors +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:191:9 + | +LL | while let Some(m) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:202:5 + | +LL | while let Some(n) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:204:9 + | +LL | while let Some(m) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:213:9 + | +LL | while let Some(m) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:222:9 + | +LL | while let Some(m) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:239:9 + | +LL | while let Some(m) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for m in &mut it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:254:13 + | +LL | while let Some(i) = self.0.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in &mut self.0` + +error: manual `!RangeInclusive::contains` implementation + --> $DIR/while_let_on_iterator.rs:255:20 + | +LL | if i < 3 || i > 7 { + | ^^^^^^^^^^^^^^ help: use: `!(3..=7).contains(&i)` + | + = note: `-D clippy::manual-range-contains` implied by `-D warnings` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:286:13 + | +LL | while let Some(i) = self.0.0.0.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for i in &mut self.0.0.0` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:315:5 + | +LL | while let Some(n) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for n in &mut it` + +error: this loop could be written as a `for` loop + --> $DIR/while_let_on_iterator.rs:325:5 + | +LL | while let Some(..) = it.next() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `for _ in it` + +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/write_with_newline.stderr b/src/tools/clippy/tests/ui/write_with_newline.stderr index a14e86122ee..cecc2ea9406 100644 --- a/src/tools/clippy/tests/ui/write_with_newline.stderr +++ b/src/tools/clippy/tests/ui/write_with_newline.stderr @@ -51,8 +51,8 @@ LL | write!(&mut v, "/n"); | help: use `writeln!()` instead | -LL | writeln!(&mut v, ); - | ^^^^^^^ -- +LL | writeln!(&mut v); + | ^^^^^^^ -- error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:36:5 diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.rs b/src/tools/clippy/tests/ui/wrong_self_convention.rs index cdfbdb8b0db..151dd0c27d5 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention.rs +++ b/src/tools/clippy/tests/ui/wrong_self_convention.rs @@ -1,6 +1,5 @@ // edition:2018 #![warn(clippy::wrong_self_convention)] -#![warn(clippy::wrong_pub_self_convention)] #![allow(dead_code)] fn main() {} diff --git a/src/tools/clippy/tests/ui/wrong_self_convention.stderr b/src/tools/clippy/tests/ui/wrong_self_convention.stderr index 29f5ba82695..ce23317abf6 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_convention.stderr @@ -1,5 +1,5 @@ error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:18:17 + --> $DIR/wrong_self_convention.rs:17:17 | LL | fn from_i32(self) {} | ^^^^ @@ -8,7 +8,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:24:21 + --> $DIR/wrong_self_convention.rs:23:21 | LL | pub fn from_i64(self) {} | ^^^^ @@ -16,7 +16,7 @@ LL | pub fn from_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:36:15 + --> $DIR/wrong_self_convention.rs:35:15 | LL | fn as_i32(self) {} | ^^^^ @@ -24,7 +24,7 @@ LL | fn as_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:38:17 + --> $DIR/wrong_self_convention.rs:37:17 | LL | fn into_i32(&self) {} | ^^^^^ @@ -32,7 +32,7 @@ LL | fn into_i32(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:40:15 + --> $DIR/wrong_self_convention.rs:39:15 | LL | fn is_i32(self) {} | ^^^^ @@ -40,7 +40,7 @@ LL | fn is_i32(self) {} = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:42:15 + --> $DIR/wrong_self_convention.rs:41:15 | LL | fn to_i32(self) {} | ^^^^ @@ -48,7 +48,7 @@ LL | fn to_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:44:17 + --> $DIR/wrong_self_convention.rs:43:17 | LL | fn from_i32(self) {} | ^^^^ @@ -56,7 +56,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:46:19 + --> $DIR/wrong_self_convention.rs:45:19 | LL | pub fn as_i64(self) {} | ^^^^ @@ -64,7 +64,7 @@ LL | pub fn as_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:47:21 + --> $DIR/wrong_self_convention.rs:46:21 | LL | pub fn into_i64(&self) {} | ^^^^^ @@ -72,7 +72,7 @@ LL | pub fn into_i64(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:48:19 + --> $DIR/wrong_self_convention.rs:47:19 | LL | pub fn is_i64(self) {} | ^^^^ @@ -80,7 +80,7 @@ LL | pub fn is_i64(self) {} = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:49:19 + --> $DIR/wrong_self_convention.rs:48:19 | LL | pub fn to_i64(self) {} | ^^^^ @@ -88,7 +88,7 @@ LL | pub fn to_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:50:21 + --> $DIR/wrong_self_convention.rs:49:21 | LL | pub fn from_i64(self) {} | ^^^^ @@ -96,7 +96,7 @@ LL | pub fn from_i64(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:95:19 + --> $DIR/wrong_self_convention.rs:94:19 | LL | fn as_i32(self) {} | ^^^^ @@ -104,7 +104,7 @@ LL | fn as_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:98:25 + --> $DIR/wrong_self_convention.rs:97:25 | LL | fn into_i32_ref(&self) {} | ^^^^^ @@ -112,7 +112,7 @@ LL | fn into_i32_ref(&self) {} = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:100:19 + --> $DIR/wrong_self_convention.rs:99:19 | LL | fn is_i32(self) {} | ^^^^ @@ -120,7 +120,7 @@ LL | fn is_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:104:21 + --> $DIR/wrong_self_convention.rs:103:21 | LL | fn from_i32(self) {} | ^^^^ @@ -128,7 +128,7 @@ LL | fn from_i32(self) {} = help: consider choosing a less ambiguous name error: methods called `as_*` usually take `self` by reference or `self` by mutable reference - --> $DIR/wrong_self_convention.rs:119:19 + --> $DIR/wrong_self_convention.rs:118:19 | LL | fn as_i32(self); | ^^^^ @@ -136,7 +136,7 @@ LL | fn as_i32(self); = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:122:25 + --> $DIR/wrong_self_convention.rs:121:25 | LL | fn into_i32_ref(&self); | ^^^^^ @@ -144,7 +144,7 @@ LL | fn into_i32_ref(&self); = help: consider choosing a less ambiguous name error: methods called `is_*` usually take `self` by reference or no `self` - --> $DIR/wrong_self_convention.rs:124:19 + --> $DIR/wrong_self_convention.rs:123:19 | LL | fn is_i32(self); | ^^^^ @@ -152,7 +152,7 @@ LL | fn is_i32(self); = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:128:21 + --> $DIR/wrong_self_convention.rs:127:21 | LL | fn from_i32(self); | ^^^^ @@ -160,7 +160,7 @@ LL | fn from_i32(self); = help: consider choosing a less ambiguous name error: methods called `into_*` usually take `self` by value - --> $DIR/wrong_self_convention.rs:146:25 + --> $DIR/wrong_self_convention.rs:145:25 | LL | fn into_i32_ref(&self); | ^^^^^ @@ -168,7 +168,7 @@ LL | fn into_i32_ref(&self); = help: consider choosing a less ambiguous name error: methods called `from_*` usually take no `self` - --> $DIR/wrong_self_convention.rs:152:21 + --> $DIR/wrong_self_convention.rs:151:21 | LL | fn from_i32(self); | ^^^^ @@ -176,7 +176,7 @@ LL | fn from_i32(self); = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is `Copy`) usually take `self` by value - --> $DIR/wrong_self_convention.rs:176:22 + --> $DIR/wrong_self_convention.rs:175:22 | LL | fn to_u64_v2(&self) -> u64 { | ^^^^^ @@ -184,7 +184,7 @@ LL | fn to_u64_v2(&self) -> u64 { = help: consider choosing a less ambiguous name error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention.rs:185:19 + --> $DIR/wrong_self_convention.rs:184:19 | LL | fn to_u64(self) -> u64 { | ^^^^ diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.rs b/src/tools/clippy/tests/ui/wrong_self_convention2.rs index ae3a740d405..501bc1e6a85 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention2.rs +++ b/src/tools/clippy/tests/ui/wrong_self_convention2.rs @@ -1,6 +1,5 @@ // edition:2018 #![warn(clippy::wrong_self_convention)] -#![warn(clippy::wrong_pub_self_convention)] #![allow(dead_code)] fn main() {} @@ -23,7 +22,7 @@ mod issue6983 { } struct FooNoCopy; - // trigger lint + // don't trigger impl ToU64 for FooNoCopy { fn to_u64(self) -> u64 { 2 @@ -42,3 +41,30 @@ mod issue7032 { } } } + +mod issue7179 { + pub struct S(i32); + + impl S { + // don't trigger (`s` is not `self`) + pub fn from_be(s: Self) -> Self { + S(i32::from_be(s.0)) + } + + // lint + pub fn from_be_self(self) -> Self { + S(i32::from_be(self.0)) + } + } + + trait T { + // don't trigger (`s` is not `self`) + fn from_be(s: Self) -> Self; + // lint + fn from_be_self(self) -> Self; + } + + trait Foo: Sized { + fn as_byte_slice(slice: &[Self]) -> &[u8]; + } +} diff --git a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr index 0ca1a390974..0e0d066d656 100644 --- a/src/tools/clippy/tests/ui/wrong_self_convention2.stderr +++ b/src/tools/clippy/tests/ui/wrong_self_convention2.stderr @@ -1,11 +1,19 @@ -error: methods with the following characteristics: (`to_*` and `self` type is not `Copy`) usually take `self` by reference - --> $DIR/wrong_self_convention2.rs:28:19 +error: methods called `from_*` usually take no `self` + --> $DIR/wrong_self_convention2.rs:55:29 | -LL | fn to_u64(self) -> u64 { - | ^^^^ +LL | pub fn from_be_self(self) -> Self { + | ^^^^ | = note: `-D clippy::wrong-self-convention` implied by `-D warnings` = help: consider choosing a less ambiguous name -error: aborting due to previous error +error: methods called `from_*` usually take no `self` + --> $DIR/wrong_self_convention2.rs:64:25 + | +LL | fn from_be_self(self) -> Self; + | ^^^^ + | + = help: consider choosing a less ambiguous name + +error: aborting due to 2 previous errors diff --git a/src/tools/clippy/util/cov.sh b/src/tools/clippy/util/cov.sh deleted file mode 100755 index 3f9a6b06f72..00000000000 --- a/src/tools/clippy/util/cov.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/bash - -# This run `kcov` on Clippy. The coverage report will be at -# `./target/cov/index.html`. -# `compile-test` is special. `kcov` does not work directly on it so these files -# are compiled manually. - -tests=$(find tests/ -maxdepth 1 -name '*.rs' ! -name compile-test.rs -exec basename {} .rs \;) -tmpdir=$(mktemp -d) - -cargo test --no-run --verbose - -for t in $tests; do - kcov \ - --verify \ - --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \ - "$tmpdir/$t" \ - cargo test --test "$t" -done - -for t in ./tests/compile-fail/*.rs; do - kcov \ - --verify \ - --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \ - "$tmpdir/compile-fail-$(basename "$t")" \ - cargo run -- -L target/debug -L target/debug/deps -Z no-trans "$t" -done - -for t in ./tests/run-pass/*.rs; do - kcov \ - --verify \ - --include-path="$(pwd)/src,$(pwd)/clippy_lints/src" \ - "$tmpdir/run-pass-$(basename "$t")" \ - cargo run -- -L target/debug -L target/debug/deps -Z no-trans "$t" -done - -kcov --verify --merge target/cov "$tmpdir"/* diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index f4e16483d8c..54b079a3e86 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2327,7 +2327,11 @@ impl<'test> TestCx<'test> { // For now, though… if let Some(rev) = self.revision { let prefixes = format!("CHECK,{}", rev); - filecheck.args(&["--check-prefixes", &prefixes]); + if self.config.llvm_version.unwrap_or(0) >= 130000 { + filecheck.args(&["--allow-unused-prefixes", "--check-prefixes", &prefixes]); + } else { + filecheck.args(&["--check-prefixes", &prefixes]); + } } self.compose_and_run(filecheck, "", None, None) } diff --git a/src/tools/jsondocck/Cargo.toml b/src/tools/jsondocck/Cargo.toml index a6efc4c9a6b..b5f1554dbe4 100644 --- a/src/tools/jsondocck/Cargo.toml +++ b/src/tools/jsondocck/Cargo.toml @@ -8,8 +8,7 @@ edition = "2018" jsonpath_lib = "0.2" getopts = "0.2" regex = "1.4" -lazy_static = "1.4" -shlex = "0.1" -serde = "1.0" +shlex = "1.0" serde_json = "1.0" fs-err = "2.5.0" +once_cell = "1.0" diff --git a/src/tools/jsondocck/src/main.rs b/src/tools/jsondocck/src/main.rs index 216890d59ad..b8ea10f3d22 100644 --- a/src/tools/jsondocck/src/main.rs +++ b/src/tools/jsondocck/src/main.rs @@ -1,5 +1,5 @@ use jsonpath_lib::select; -use lazy_static::lazy_static; +use once_cell::sync::Lazy; use regex::{Regex, RegexBuilder}; use serde_json::Value; use std::borrow::Cow; @@ -94,19 +94,19 @@ impl fmt::Display for CommandKind { } } -lazy_static! { - static ref LINE_PATTERN: Regex = RegexBuilder::new( +static LINE_PATTERN: Lazy<Regex> = Lazy::new(|| { + RegexBuilder::new( r#" \s(?P<invalid>!?)@(?P<negated>!?) (?P<cmd>[A-Za-z]+(?:-[A-Za-z]+)*) (?P<args>.*)$ - "# + "#, ) .ignore_whitespace(true) .unicode(true) .build() - .unwrap(); -} + .unwrap() +}); fn print_err(msg: &str, lineno: usize) { eprintln!("Invalid command: {} on line {}", msg, lineno) diff --git a/src/tools/linkchecker/linkcheck.sh b/src/tools/linkchecker/linkcheck.sh index b68053c76be..9eeebf444a4 100755 --- a/src/tools/linkchecker/linkcheck.sh +++ b/src/tools/linkchecker/linkcheck.sh @@ -85,11 +85,11 @@ fi if [ ! -e "linkchecker/main.rs" ] || [ "$iterative" = "0" ] then echo "Downloading linkchecker source..." + nightly_hash=$(rustc +nightly -Vv | grep commit-hash | cut -f2 -d" ") + url="https://raw.githubusercontent.com/rust-lang/rust" mkdir linkchecker - curl -o linkchecker/Cargo.toml \ - https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/Cargo.toml - curl -o linkchecker/main.rs \ - https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/main.rs + curl -o linkchecker/Cargo.toml ${url}/${nightly_hash}/src/tools/linkchecker/Cargo.toml + curl -o linkchecker/main.rs ${url}/${nightly_hash}/src/tools/linkchecker/main.rs fi echo "Building book \"$book_name\"..." @@ -106,7 +106,7 @@ else check_path="linkcheck/$book_name" fi echo "Running linkchecker on \"$check_path\"..." -cargo run --manifest-path=linkchecker/Cargo.toml -- "$check_path" +cargo run --release --manifest-path=linkchecker/Cargo.toml -- "$check_path" if [ "$iterative" = "0" ] then diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index c677d04917e..47960c3f6cc 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -14,18 +14,18 @@ //! A few exceptions are allowed as there's known bugs in rustdoc, but this //! should catch the majority of "broken link" cases. -use std::collections::hash_map::Entry; +use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::env; use std::fs; +use std::io::ErrorKind; use std::path::{Component, Path, PathBuf}; use std::rc::Rc; +use std::time::Instant; use once_cell::sync::Lazy; use regex::Regex; -use crate::Redirect::*; - // Add linkcheck exceptions here // If at all possible you should use intra-doc links to avoid linkcheck issues. These // are cases where that does not work @@ -87,33 +87,64 @@ macro_rules! t { } fn main() { - let docs = env::args_os().nth(1).unwrap(); + let docs = env::args_os().nth(1).expect("doc path should be first argument"); let docs = env::current_dir().unwrap().join(docs); - let mut errors = false; - walk(&mut HashMap::new(), &docs, &docs, &mut errors); - if errors { - panic!("found some broken links"); + let mut checker = Checker { root: docs.clone(), cache: HashMap::new() }; + let mut report = Report { + errors: 0, + start: Instant::now(), + html_files: 0, + html_redirects: 0, + links_checked: 0, + links_ignored_external: 0, + links_ignored_exception: 0, + intra_doc_exceptions: 0, + }; + checker.walk(&docs, &mut report); + report.report(); + if report.errors != 0 { + println!("found some broken links"); + std::process::exit(1); } } -#[derive(Debug)] -pub enum LoadError { - IOError(std::io::Error), - BrokenRedirect(PathBuf, std::io::Error), - IsRedirect, +struct Checker { + root: PathBuf, + cache: Cache, } -enum Redirect { - SkipRedirect, - FromRedirect(bool), +struct Report { + errors: u32, + start: Instant, + html_files: u32, + html_redirects: u32, + links_checked: u32, + links_ignored_external: u32, + links_ignored_exception: u32, + intra_doc_exceptions: u32, } -struct FileEntry { - source: Rc<String>, - ids: HashSet<String>, +/// A cache entry. +enum FileEntry { + /// An HTML file. + /// + /// This includes the contents of the HTML file, and an optional set of + /// HTML IDs. The IDs are used for checking fragments. The are computed + /// as-needed. The source is discarded (replaced with an empty string) + /// after the file has been checked, to conserve on memory. + HtmlFile { source: Rc<String>, ids: RefCell<HashSet<String>> }, + /// This file is an HTML redirect to the given local path. + Redirect { target: PathBuf }, + /// This is not an HTML file. + OtherFile, + /// This is a directory. + Dir, + /// The file doesn't exist. + Missing, } -type Cache = HashMap<PathBuf, FileEntry>; +/// A cache to speed up file access. +type Cache = HashMap<String, FileEntry>; fn small_url_encode(s: &str) -> String { s.replace("<", "%3C") @@ -130,173 +161,169 @@ fn small_url_encode(s: &str) -> String { .replace("\"", "%22") } -impl FileEntry { - fn parse_ids(&mut self, file: &Path, contents: &str, errors: &mut bool) { - if self.ids.is_empty() { - with_attrs_in_source(contents, " id", |fragment, i, _| { - let frag = fragment.trim_start_matches("#").to_owned(); - let encoded = small_url_encode(&frag); - if !self.ids.insert(frag) { - *errors = true; - println!("{}:{}: id is not unique: `{}`", file.display(), i, fragment); - } - // Just in case, we also add the encoded id. - self.ids.insert(encoded); - }); - } - } -} - -fn walk(cache: &mut Cache, root: &Path, dir: &Path, errors: &mut bool) { - for entry in t!(dir.read_dir()).map(|e| t!(e)) { - let path = entry.path(); - let kind = t!(entry.file_type()); - if kind.is_dir() { - walk(cache, root, &path, errors); - } else { - let pretty_path = check(cache, root, &path, errors); - if let Some(pretty_path) = pretty_path { - let entry = cache.get_mut(&pretty_path).unwrap(); - // we don't need the source anymore, - // so drop to reduce memory-usage - entry.source = Rc::new(String::new()); +impl Checker { + /// Primary entry point for walking the filesystem to find HTML files to check. + fn walk(&mut self, dir: &Path, report: &mut Report) { + for entry in t!(dir.read_dir()).map(|e| t!(e)) { + let path = entry.path(); + let kind = t!(entry.file_type()); + if kind.is_dir() { + self.walk(&path, report); + } else { + self.check(&path, report); } } } -} - -fn is_intra_doc_exception(file: &Path, link: &str) -> bool { - if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) { - entry.1.is_empty() || entry.1.contains(&link) - } else { - false - } -} -fn is_exception(file: &Path, link: &str) -> bool { - if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) { - entry.1.contains(&link) - } else { - // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page - // - // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path - // calculated in `check` function is outside `build/<triple>/doc` dir. - // So the `strip_prefix` method just returns the old absolute broken path. - if file.ends_with("std/primitive.slice.html") { - if link.ends_with("primitive.slice.html") { - return true; + /// Checks a single file. + fn check(&mut self, file: &Path, report: &mut Report) { + let (pretty_path, entry) = self.load_file(file, report); + let source = match entry { + FileEntry::Missing => panic!("missing file {:?} while walking", file), + FileEntry::Dir => unreachable!("never with `check` path"), + FileEntry::OtherFile => return, + FileEntry::Redirect { .. } => return, + FileEntry::HtmlFile { source, ids } => { + parse_ids(&mut ids.borrow_mut(), &pretty_path, source, report); + source.clone() } - } - false - } -} - -fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Option<PathBuf> { - // Ignore non-HTML files. - if file.extension().and_then(|s| s.to_str()) != Some("html") { - return None; - } + }; - let res = load_file(cache, root, file, SkipRedirect); - let (pretty_file, contents) = match res { - Ok(res) => res, - Err(_) => return None, - }; - { - cache.get_mut(&pretty_file).unwrap().parse_ids(&pretty_file, &contents, errors); - } + // Search for anything that's the regex 'href[ ]*=[ ]*".*?"' + with_attrs_in_source(&source, " href", |url, i, base| { + // Ignore external URLs + if url.starts_with("http:") + || url.starts_with("https:") + || url.starts_with("javascript:") + || url.starts_with("ftp:") + || url.starts_with("irc:") + || url.starts_with("data:") + { + report.links_ignored_external += 1; + return; + } + report.links_checked += 1; + let (url, fragment) = match url.split_once('#') { + None => (url, None), + Some((url, fragment)) => (url, Some(fragment)), + }; + // NB: the `splitn` always succeeds, even if the delimiter is not present. + let url = url.splitn(2, '?').next().unwrap(); + + // Once we've plucked out the URL, parse it using our base url and + // then try to extract a file path. + let mut path = file.to_path_buf(); + if !base.is_empty() || !url.is_empty() { + path.pop(); + for part in Path::new(base).join(url).components() { + match part { + Component::Prefix(_) | Component::RootDir => { + // Avoid absolute paths as they make the docs not + // relocatable by making assumptions on where the docs + // are hosted relative to the site root. + report.errors += 1; + println!( + "{}:{}: absolute path - {}", + pretty_path, + i + 1, + Path::new(base).join(url).display() + ); + return; + } + Component::CurDir => {} + Component::ParentDir => { + path.pop(); + } + Component::Normal(s) => { + path.push(s); + } + } + } + } - // Search for anything that's the regex 'href[ ]*=[ ]*".*?"' - with_attrs_in_source(&contents, " href", |url, i, base| { - // Ignore external URLs - if url.starts_with("http:") - || url.starts_with("https:") - || url.starts_with("javascript:") - || url.starts_with("ftp:") - || url.starts_with("irc:") - || url.starts_with("data:") - { - return; - } - let (url, fragment) = match url.split_once('#') { - None => (url, None), - Some((url, fragment)) => (url, Some(fragment)), - }; - // NB: the `splitn` always succeeds, even if the delimiter is not present. - let url = url.splitn(2, '?').next().unwrap(); - - // Once we've plucked out the URL, parse it using our base url and - // then try to extract a file path. - let mut path = file.to_path_buf(); - if !base.is_empty() || !url.is_empty() { - path.pop(); - for part in Path::new(base).join(url).components() { - match part { - Component::Prefix(_) | Component::RootDir => { - // Avoid absolute paths as they make the docs not - // relocatable by making assumptions on where the docs - // are hosted relative to the site root. - *errors = true; + let (target_pretty_path, target_entry) = self.load_file(&path, report); + let (target_source, target_ids) = match target_entry { + FileEntry::Missing => { + if is_exception(file, &target_pretty_path) { + report.links_ignored_exception += 1; + } else { + report.errors += 1; println!( - "{}:{}: absolute path - {}", - pretty_file.display(), + "{}:{}: broken link - `{}`", + pretty_path, i + 1, - Path::new(base).join(url).display() + target_pretty_path ); - return; - } - Component::CurDir => {} - Component::ParentDir => { - path.pop(); } - Component::Normal(s) => { - path.push(s); - } - } - } - } - - // Alright, if we've found a file name then this file had better - // exist! If it doesn't then we register and print an error. - if path.exists() { - if path.is_dir() { - // Links to directories show as directory listings when viewing - // the docs offline so it's best to avoid them. - *errors = true; - let pretty_path = path.strip_prefix(root).unwrap_or(&path); - println!( - "{}:{}: directory link - {}", - pretty_file.display(), - i + 1, - pretty_path.display() - ); - return; - } - if let Some(extension) = path.extension() { - // Ignore none HTML files. - if extension != "html" { return; } - } - let res = load_file(cache, root, &path, FromRedirect(false)); - let (pretty_path, contents) = match res { - Ok(res) => res, - Err(LoadError::IOError(err)) => { - panic!("error loading {}: {}", path.display(), err); - } - Err(LoadError::BrokenRedirect(target, _)) => { - *errors = true; + FileEntry::Dir => { + // Links to directories show as directory listings when viewing + // the docs offline so it's best to avoid them. + report.errors += 1; println!( - "{}:{}: broken redirect to {}", - pretty_file.display(), + "{}:{}: directory link to `{}` \ + (directory links should use index.html instead)", + pretty_path, i + 1, - target.display() + target_pretty_path ); return; } - Err(LoadError::IsRedirect) => unreachable!(), + FileEntry::OtherFile => return, + FileEntry::Redirect { target } => { + let t = target.clone(); + drop(target); + let (target, redir_entry) = self.load_file(&t, report); + match redir_entry { + FileEntry::Missing => { + report.errors += 1; + println!( + "{}:{}: broken redirect from `{}` to `{}`", + pretty_path, + i + 1, + target_pretty_path, + target + ); + return; + } + FileEntry::Redirect { target } => { + // Redirect to a redirect, this link checker + // currently doesn't support this, since it would + // require cycle checking, etc. + report.errors += 1; + println!( + "{}:{}: redirect from `{}` to `{}` \ + which is also a redirect (not supported)", + pretty_path, + i + 1, + target_pretty_path, + target.display() + ); + return; + } + FileEntry::Dir => { + report.errors += 1; + println!( + "{}:{}: redirect from `{}` to `{}` \ + which is a directory \ + (directory links should use index.html instead)", + pretty_path, + i + 1, + target_pretty_path, + target + ); + return; + } + FileEntry::OtherFile => return, + FileEntry::HtmlFile { source, ids } => (source, ids), + } + } + FileEntry::HtmlFile { source, ids } => (source, ids), }; + // Alright, if we've found an HTML file for the target link. If + // this is a fragment link, also check that the `id` exists. if let Some(ref fragment) = fragment { // Fragments like `#1-6` are most likely line numbers to be // interpreted by javascript, so we're ignoring these @@ -309,85 +336,134 @@ fn check(cache: &mut Cache, root: &Path, file: &Path, errors: &mut bool) -> Opti return; } - let entry = &mut cache.get_mut(&pretty_path).unwrap(); - entry.parse_ids(&pretty_path, &contents, errors); + parse_ids(&mut target_ids.borrow_mut(), &pretty_path, target_source, report); + + if target_ids.borrow().contains(*fragment) { + return; + } - if !entry.ids.contains(*fragment) && !is_exception(file, &format!("#{}", fragment)) - { - *errors = true; - print!("{}:{}: broken link fragment ", pretty_file.display(), i + 1); - println!("`#{}` pointing to `{}`", fragment, pretty_path.display()); + if is_exception(file, &format!("#{}", fragment)) { + report.links_ignored_exception += 1; + } else { + report.errors += 1; + print!("{}:{}: broken link fragment ", pretty_path, i + 1); + println!("`#{}` pointing to `{}`", fragment, pretty_path); }; } - } else { - let pretty_path = path.strip_prefix(root).unwrap_or(&path); - if !is_exception(file, pretty_path.to_str().unwrap()) { - *errors = true; - print!("{}:{}: broken link - ", pretty_file.display(), i + 1); - println!("{}", pretty_path.display()); + }); + + // Search for intra-doc links that rustdoc didn't warn about + // FIXME(#77199, 77200) Rustdoc should just warn about these directly. + // NOTE: only looks at one line at a time; in practice this should find most links + for (i, line) in source.lines().enumerate() { + for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) { + if is_intra_doc_exception(file, &broken_link[1]) { + report.intra_doc_exceptions += 1; + } else { + report.errors += 1; + print!("{}:{}: broken intra-doc link - ", pretty_path, i + 1); + println!("{}", &broken_link[0]); + } } } - }); - - // Search for intra-doc links that rustdoc didn't warn about - // FIXME(#77199, 77200) Rustdoc should just warn about these directly. - // NOTE: only looks at one line at a time; in practice this should find most links - for (i, line) in contents.lines().enumerate() { - for broken_link in BROKEN_INTRA_DOC_LINK.captures_iter(line) { - if !is_intra_doc_exception(file, &broken_link[1]) { - *errors = true; - print!("{}:{}: broken intra-doc link - ", pretty_file.display(), i + 1); - println!("{}", &broken_link[0]); - } + // we don't need the source anymore, + // so drop to reduce memory-usage + match self.cache.get_mut(&pretty_path).unwrap() { + FileEntry::HtmlFile { source, .. } => *source = Rc::new(String::new()), + _ => unreachable!("must be html file"), } } - Some(pretty_file) -} -fn load_file( - cache: &mut Cache, - root: &Path, - file: &Path, - redirect: Redirect, -) -> Result<(PathBuf, Rc<String>), LoadError> { - let pretty_file = PathBuf::from(file.strip_prefix(root).unwrap_or(&file)); - - let (maybe_redirect, contents) = match cache.entry(pretty_file.clone()) { - Entry::Occupied(entry) => (None, entry.get().source.clone()), - Entry::Vacant(entry) => { - let contents = match fs::read_to_string(file) { - Ok(s) => Rc::new(s), - Err(err) => { - return Err(if let FromRedirect(true) = redirect { - LoadError::BrokenRedirect(file.to_path_buf(), err) + /// Load a file from disk, or from the cache if available. + fn load_file(&mut self, file: &Path, report: &mut Report) -> (String, &FileEntry) { + let pretty_path = + file.strip_prefix(&self.root).unwrap_or(&file).to_str().unwrap().to_string(); + + let entry = + self.cache.entry(pretty_path.clone()).or_insert_with(|| match fs::metadata(file) { + Ok(metadata) if metadata.is_dir() => FileEntry::Dir, + Ok(_) => { + if file.extension().and_then(|s| s.to_str()) != Some("html") { + FileEntry::OtherFile } else { - LoadError::IOError(err) - }); + report.html_files += 1; + load_html_file(file, report) + } } - }; - - let maybe = maybe_redirect(&contents); - if maybe.is_some() { - if let SkipRedirect = redirect { - return Err(LoadError::IsRedirect); + Err(e) if e.kind() == ErrorKind::NotFound => FileEntry::Missing, + Err(e) => { + panic!("unexpected read error for {}: {}", file.display(), e); } - } else { - entry.insert(FileEntry { source: contents.clone(), ids: HashSet::new() }); - } - (maybe, contents) + }); + (pretty_path, entry) + } +} + +impl Report { + fn report(&self) { + println!("checked links in: {:.1}s", self.start.elapsed().as_secs_f64()); + println!("number of HTML files scanned: {}", self.html_files); + println!("number of HTML redirects found: {}", self.html_redirects); + println!("number of links checked: {}", self.links_checked); + println!("number of links ignored due to external: {}", self.links_ignored_external); + println!("number of links ignored due to exceptions: {}", self.links_ignored_exception); + println!("number of intra doc links ignored: {}", self.intra_doc_exceptions); + println!("errors found: {}", self.errors); + } +} + +fn load_html_file(file: &Path, report: &mut Report) -> FileEntry { + let source = match fs::read_to_string(file) { + Ok(s) => Rc::new(s), + Err(err) => { + // This usually should not fail since `metadata` was already + // called successfully on this file. + panic!("unexpected read error for {}: {}", file.display(), err); } }; - match maybe_redirect.map(|url| file.parent().unwrap().join(url)) { - Some(redirect_file) => load_file(cache, root, &redirect_file, FromRedirect(true)), - None => Ok((pretty_file, contents)), + match maybe_redirect(&source) { + Some(target) => { + report.html_redirects += 1; + let target = file.parent().unwrap().join(target); + FileEntry::Redirect { target } + } + None => FileEntry::HtmlFile { source: source.clone(), ids: RefCell::new(HashSet::new()) }, + } +} + +fn is_intra_doc_exception(file: &Path, link: &str) -> bool { + if let Some(entry) = INTRA_DOC_LINK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) { + entry.1.is_empty() || entry.1.contains(&link) + } else { + false } } +fn is_exception(file: &Path, link: &str) -> bool { + if let Some(entry) = LINKCHECK_EXCEPTIONS.iter().find(|&(f, _)| file.ends_with(f)) { + entry.1.contains(&link) + } else { + // FIXME(#63351): Concat trait in alloc/slice reexported in primitive page + // + // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path + // calculated in `check` function is outside `build/<triple>/doc` dir. + // So the `strip_prefix` method just returns the old absolute broken path. + if file.ends_with("std/primitive.slice.html") { + if link.ends_with("primitive.slice.html") { + return true; + } + } + false + } +} + +/// If the given HTML file contents is an HTML redirect, this returns the +/// destination path given in the redirect. fn maybe_redirect(source: &str) -> Option<String> { const REDIRECT: &str = "<p>Redirecting to <a href="; let mut lines = source.lines(); - let redirect_line = lines.nth(6)?; + let redirect_line = lines.nth(7)?; redirect_line.find(REDIRECT).map(|i| { let rest = &redirect_line[(i + REDIRECT.len() + 1)..]; @@ -396,9 +472,9 @@ fn maybe_redirect(source: &str) -> Option<String> { }) } -fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(contents: &str, attr: &str, mut f: F) { +fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(source: &str, attr: &str, mut f: F) { let mut base = ""; - for (i, mut line) in contents.lines().enumerate() { + for (i, mut line) in source.lines().enumerate() { while let Some(j) = line.find(attr) { let rest = &line[j + attr.len()..]; // The base tag should always be the first link in the document so @@ -437,3 +513,18 @@ fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(contents: &str, attr: &str, } } } + +fn parse_ids(ids: &mut HashSet<String>, file: &str, source: &str, report: &mut Report) { + if ids.is_empty() { + with_attrs_in_source(source, " id", |fragment, i, _| { + let frag = fragment.trim_start_matches("#").to_owned(); + let encoded = small_url_encode(&frag); + if !ids.insert(frag) { + report.errors += 1; + println!("{}:{}: id is not unique: `{}`", file, i, fragment); + } + // Just in case, we also add the encoded id. + ids.insert(encoded); + }); + } +} diff --git a/src/tools/linkchecker/tests/basic_broken/foo.html b/src/tools/linkchecker/tests/basic_broken/foo.html new file mode 100644 index 00000000000..cb27c55c9fe --- /dev/null +++ b/src/tools/linkchecker/tests/basic_broken/foo.html @@ -0,0 +1,5 @@ +<html> +<body> +<a href="bar.html">test</a> +</body> +</html> diff --git a/src/tools/linkchecker/tests/broken_fragment_local/foo.html b/src/tools/linkchecker/tests/broken_fragment_local/foo.html new file mode 100644 index 00000000000..66c457ad01f --- /dev/null +++ b/src/tools/linkchecker/tests/broken_fragment_local/foo.html @@ -0,0 +1,5 @@ +<html> +<body> +<a href="#somefrag">test</a> +</body> +</html> diff --git a/src/tools/linkchecker/tests/broken_fragment_remote/bar.html b/src/tools/linkchecker/tests/broken_fragment_remote/bar.html new file mode 100644 index 00000000000..7879e1ce9fd --- /dev/null +++ b/src/tools/linkchecker/tests/broken_fragment_remote/bar.html @@ -0,0 +1,4 @@ +<html> +<body> +</body> +</html> diff --git a/src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html b/src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html new file mode 100644 index 00000000000..7683060b3a6 --- /dev/null +++ b/src/tools/linkchecker/tests/broken_fragment_remote/inner/foo.html @@ -0,0 +1,5 @@ +<html> +<body> +<a href="../bar.html#somefrag">test</a> +</body> +</html> diff --git a/src/tools/linkchecker/tests/broken_redir/foo.html b/src/tools/linkchecker/tests/broken_redir/foo.html new file mode 100644 index 00000000000..bd3e3ad3343 --- /dev/null +++ b/src/tools/linkchecker/tests/broken_redir/foo.html @@ -0,0 +1,5 @@ +<html> +<body> + <a href="redir-bad.html">bad redir</a> +</body> +</html> diff --git a/src/tools/linkchecker/tests/broken_redir/redir-bad.html b/src/tools/linkchecker/tests/broken_redir/redir-bad.html new file mode 100644 index 00000000000..3e376629f74 --- /dev/null +++ b/src/tools/linkchecker/tests/broken_redir/redir-bad.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta http-equiv="refresh" content="0;URL=sometarget"> +</head> +<body> + <p>Redirecting to <a href="sometarget">sometarget</a>...</p> + <script>location.replace("sometarget" + location.search + location.hash);</script> +</body> +</html> diff --git a/src/tools/linkchecker/tests/checks.rs b/src/tools/linkchecker/tests/checks.rs new file mode 100644 index 00000000000..c6ec999e5cf --- /dev/null +++ b/src/tools/linkchecker/tests/checks.rs @@ -0,0 +1,77 @@ +use std::path::Path; +use std::process::{Command, ExitStatus}; + +fn run(dirname: &str) -> (ExitStatus, String, String) { + let output = Command::new(env!("CARGO_BIN_EXE_linkchecker")) + .current_dir(Path::new(env!("CARGO_MANIFEST_DIR")).join("tests")) + .arg(dirname) + .output() + .unwrap(); + let stdout = String::from_utf8(output.stdout).unwrap(); + let stderr = String::from_utf8(output.stderr).unwrap(); + (output.status, stdout, stderr) +} + +fn broken_test(dirname: &str, expected: &str) { + let (status, stdout, stderr) = run(dirname); + assert!(!status.success()); + if !stdout.contains(expected) { + panic!( + "stdout did not contain expected text: {}\n\ + --- stdout:\n\ + {}\n\ + --- stderr:\n\ + {}\n", + expected, stdout, stderr + ); + } +} + +fn valid_test(dirname: &str) { + let (status, stdout, stderr) = run(dirname); + if !status.success() { + panic!( + "test did not succeed as expected\n\ + --- stdout:\n\ + {}\n\ + --- stderr:\n\ + {}\n", + stdout, stderr + ); + } +} + +#[test] +fn valid() { + valid_test("valid/inner"); +} + +#[test] +fn basic_broken() { + broken_test("basic_broken", "bar.html"); +} + +#[test] +fn broken_fragment_local() { + broken_test("broken_fragment_local", "#somefrag"); +} + +#[test] +fn broken_fragment_remote() { + broken_test("broken_fragment_remote/inner", "#somefrag"); +} + +#[test] +fn broken_redir() { + broken_test("broken_redir", "sometarget"); +} + +#[test] +fn directory_link() { + broken_test("directory_link", "somedir"); +} + +#[test] +fn redirect_loop() { + broken_test("redirect_loop", "redir-bad.html"); +} diff --git a/src/tools/linkchecker/tests/directory_link/foo.html b/src/tools/linkchecker/tests/directory_link/foo.html new file mode 100644 index 00000000000..40a8461b86c --- /dev/null +++ b/src/tools/linkchecker/tests/directory_link/foo.html @@ -0,0 +1,5 @@ +<html> +<body> + <a href="somedir">dir link</a> +</body> +</html> diff --git a/src/tools/linkchecker/tests/directory_link/somedir/index.html b/src/tools/linkchecker/tests/directory_link/somedir/index.html new file mode 100644 index 00000000000..7879e1ce9fd --- /dev/null +++ b/src/tools/linkchecker/tests/directory_link/somedir/index.html @@ -0,0 +1,4 @@ +<html> +<body> +</body> +</html> diff --git a/src/tools/linkchecker/tests/redirect_loop/foo.html b/src/tools/linkchecker/tests/redirect_loop/foo.html new file mode 100644 index 00000000000..bee58b212b5 --- /dev/null +++ b/src/tools/linkchecker/tests/redirect_loop/foo.html @@ -0,0 +1,5 @@ +<html> +<body> + <a href="redir-bad.html">loop link</a> +</body> +</html> diff --git a/src/tools/linkchecker/tests/redirect_loop/redir-bad.html b/src/tools/linkchecker/tests/redirect_loop/redir-bad.html new file mode 100644 index 00000000000..fe7780e6739 --- /dev/null +++ b/src/tools/linkchecker/tests/redirect_loop/redir-bad.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta http-equiv="refresh" content="0;URL=redir-bad.html"> +</head> +<body> + <p>Redirecting to <a href="redir-bad.html">redir-bad.html</a>...</p> + <script>location.replace("redir-bad.html" + location.search + location.hash);</script> +</body> +</html> diff --git a/src/tools/linkchecker/tests/valid/inner/bar.html b/src/tools/linkchecker/tests/valid/inner/bar.html new file mode 100644 index 00000000000..4b500d78b76 --- /dev/null +++ b/src/tools/linkchecker/tests/valid/inner/bar.html @@ -0,0 +1,7 @@ +<html> +<body> + + <h2 id="barfrag">Bar</h2> + +</body> +</html> diff --git a/src/tools/linkchecker/tests/valid/inner/foo.html b/src/tools/linkchecker/tests/valid/inner/foo.html new file mode 100644 index 00000000000..3c6a7483bcd --- /dev/null +++ b/src/tools/linkchecker/tests/valid/inner/foo.html @@ -0,0 +1,14 @@ +<html> +<body> + <a href="#localfrag">test local frag</a> + <a href="../outer.html">remote link</a> + <a href="../outer.html#somefrag">remote link with fragment</a> + <a href="bar.html">this book</a> + <a href="bar.html#barfrag">this book with fragment</a> + <a href="https://example.com/doesnotexist">external links not validated</a> + <a href="redir.html#redirfrag">Redirect</a> + + <h2 id="localfrag">Local</h2> + +</body> +</html> diff --git a/src/tools/linkchecker/tests/valid/inner/redir-bad.html b/src/tools/linkchecker/tests/valid/inner/redir-bad.html new file mode 100644 index 00000000000..d21336e7e73 --- /dev/null +++ b/src/tools/linkchecker/tests/valid/inner/redir-bad.html @@ -0,0 +1,11 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta http-equiv="refresh" content="0;URL=xxx"> +</head> +<body> + <p>Redirecting to <a href="xxx">xxx</a>...</p> + <script>location.replace("xxx" + location.search + location.hash);</script> + These files are skipped, but probably shouldn't be. +</body> +</html> diff --git a/src/tools/linkchecker/tests/valid/inner/redir-target.html b/src/tools/linkchecker/tests/valid/inner/redir-target.html new file mode 100644 index 00000000000..bd59884a01e --- /dev/null +++ b/src/tools/linkchecker/tests/valid/inner/redir-target.html @@ -0,0 +1,5 @@ +<html> +<body> + <h2 id="redirfrag">Redir</h2> +</body> +</html> diff --git a/src/tools/linkchecker/tests/valid/inner/redir.html b/src/tools/linkchecker/tests/valid/inner/redir.html new file mode 100644 index 00000000000..1808b23aed8 --- /dev/null +++ b/src/tools/linkchecker/tests/valid/inner/redir.html @@ -0,0 +1,10 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta http-equiv="refresh" content="0;URL=redir-target.html"> +</head> +<body> + <p>Redirecting to <a href="redir-target.html">redir-target.html</a>...</p> + <script>location.replace("redir-target.html" + location.search + location.hash);</script> +</body> +</html> diff --git a/src/tools/linkchecker/tests/valid/outer.html b/src/tools/linkchecker/tests/valid/outer.html new file mode 100644 index 00000000000..35f799f2023 --- /dev/null +++ b/src/tools/linkchecker/tests/valid/outer.html @@ -0,0 +1,5 @@ +<html> +<body> +<a id="somefrag"></a> +</body> +</html> diff --git a/src/tools/miri b/src/tools/miri -Subproject bcae3315a76876eb48e06519749cfe6e453a8e9 +Subproject 5dde0fe6de2941c9ef16bc1e9d91ecf20ac5ee8 diff --git a/src/tools/rls b/src/tools/rls -Subproject 097d8908339e20435078233a55a1a3335fe7c2e +Subproject 9ed6f96f2ff85753c5a6ac290ee88ecb2831ab2 diff --git a/src/tools/rust-analyzer b/src/tools/rust-analyzer -Subproject fd109fb587904cfecc1149e068814bfd38feb83 +Subproject f4383981249d3f2964f2c667f3349f8ff15b77c diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js index 298fc7519fa..c55e014e834 100644 --- a/src/tools/rustdoc-gui/tester.js +++ b/src/tools/rustdoc-gui/tester.js @@ -63,6 +63,13 @@ async function main(argv) { // This is more convenient that setting fields one by one. options.parseArguments([ "--no-screenshot", + // This option shows what puppeteer "code" is run + // "--debug", + // This option disable the headless mode, allowing you to see what's going on. + // "--no-headless", + // The text isn't rendered by default because of a lot of small differences + // between hosts. + // "--show-text", "--variable", "DOC_PATH", opts["doc_folder"], ]); } catch (error) { diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index bba689d07a4..06cec1964a0 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -235,7 +235,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "ar", "autocfg", "bitflags", - "byteorder", "cfg-if", "cranelift-bforest", "cranelift-codegen", @@ -248,9 +247,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "cranelift-native", "cranelift-object", "crc32fast", - "errno", - "errno-dragonfly", - "gcc", "gimli", "hashbrown", "indexmap", @@ -259,17 +255,11 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "log", "mach", "object", - "proc-macro2", - "quote", "regalloc", "region", "rustc-hash", "smallvec", - "syn", "target-lexicon", - "thiserror", - "thiserror-impl", - "unicode-xid", "winapi", "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index 55f824b63f2..d6e0ebaa541 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -8,15 +8,14 @@ use std::path::Path; // A few of those error codes can't be tested but all the others can and *should* be tested! const EXEMPTED_FROM_TEST: &[&str] = &[ - "E0183", "E0227", "E0279", "E0280", "E0311", "E0313", "E0314", "E0315", "E0377", "E0461", - "E0462", "E0464", "E0465", "E0472", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480", - "E0481", "E0482", "E0483", "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514", - "E0519", "E0523", "E0553", "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0727", - "E0729", + "E0227", "E0279", "E0280", "E0313", "E0314", "E0315", "E0377", "E0461", "E0462", "E0464", + "E0465", "E0473", "E0474", "E0475", "E0476", "E0479", "E0480", "E0481", "E0482", "E0483", + "E0484", "E0485", "E0486", "E0487", "E0488", "E0489", "E0514", "E0519", "E0523", "E0553", + "E0554", "E0570", "E0629", "E0630", "E0640", "E0717", "E0729", ]; // Some error codes don't have any tests apparently... -const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0639", "E0729"]; +const IGNORE_EXPLANATION_CHECK: &[&str] = &["E0570", "E0601", "E0602", "E0729"]; fn check_error_code_explanation( f: &str, @@ -114,13 +113,18 @@ fn extract_error_codes( .expect("failed to canonicalize error explanation file path"); match read_to_string(&path) { Ok(content) => { - if !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) - && !check_if_error_code_is_test_in_explanation(&content, &err_code) - { + let has_test = check_if_error_code_is_test_in_explanation(&content, &err_code); + if !has_test && !IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) { errors.push(format!( "`{}` doesn't use its own error code in compile_fail example", path.display(), )); + } else if has_test && IGNORE_EXPLANATION_CHECK.contains(&err_code.as_str()) { + errors.push(format!( + "`{}` has a compile_fail example with its own error code, it shouldn't \ + be listed in IGNORE_EXPLANATION_CHECK!", + path.display(), + )); } if check_error_code_explanation(&content, error_codes, err_code) { errors.push(format!( @@ -198,6 +202,11 @@ pub fn check(paths: &[&Path], bad: &mut bool) { for (err_code, nb) in &error_codes { if !*nb && !EXEMPTED_FROM_TEST.contains(&err_code.as_str()) { errors.push(format!("Error code {} needs to have at least one UI test!", err_code)); + } else if *nb && EXEMPTED_FROM_TEST.contains(&err_code.as_str()) { + errors.push(format!( + "Error code {} has a UI test, it shouldn't be listed into EXEMPTED_FROM_TEST!", + err_code + )); } } } diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 7b42de0ec43..f61295c8830 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -7,8 +7,8 @@ use std::path::Path; const ENTRY_LIMIT: usize = 1000; // FIXME: The following limits should be reduced eventually. -const ROOT_ENTRY_LIMIT: usize = 1370; -const ISSUES_ENTRY_LIMIT: usize = 2555; +const ROOT_ENTRY_LIMIT: usize = 1371; +const ISSUES_ENTRY_LIMIT: usize = 2559; fn check_entries(path: &Path, bad: &mut bool) { let dirs = walkdir::WalkDir::new(&path.join("test/ui")) diff --git a/src/tools/tier-check/src/main.rs b/src/tools/tier-check/src/main.rs index 6a492bbff4d..a41e2d6e3aa 100644 --- a/src/tools/tier-check/src/main.rs +++ b/src/tools/tier-check/src/main.rs @@ -24,7 +24,7 @@ fn main() { let doc_targets_md = std::fs::read_to_string(&src).expect("failed to read input source"); let doc_targets: HashSet<_> = doc_targets_md .lines() - .filter(|line| line.starts_with('`') && line.contains('|')) + .filter(|line| line.starts_with(&['`', '['][..]) && line.contains('|')) .map(|line| line.split('`').skip(1).next().expect("expected target code span")) .collect(); diff --git a/triagebot.toml b/triagebot.toml index 8b6157cd4aa..c97f63f1cfd 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -79,7 +79,7 @@ trigger_labels = [ "regression-from-stable-to-stable", "regression-from-stable-to-beta", "regression-from-stable-to-nightly", - "I-unsound 💥", + "I-unsound", ] exclude_labels = [ "P-*", |
