diff options
979 files changed, 18398 insertions, 7614 deletions
diff --git a/Cargo.lock b/Cargo.lock index bb37fee98e4..04c804d19a4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -154,11 +154,11 @@ checksum = "98161a4e3e2184da77bb14f02184cdd111e83bbbcc9979dfee3c44b9a85f5602" [[package]] name = "ar_archive_writer" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0639441fd17a3197d1cbca8dc8768cc172a63b64b4bb6c372e8f41ed0acc9bb" +checksum = "74cfb39880a59e122232cb5fb06b20b4382d58c12fa9747d16f846d38a7b094c" dependencies = [ - "object", + "object 0.31.1", ] [[package]] @@ -233,7 +233,7 @@ dependencies = [ "cfg-if", "libc", "miniz_oxide", - "object", + "object 0.30.1", "rustc-demangle", ] @@ -332,6 +332,12 @@ dependencies = [ ] [[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] name = "bytes" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -629,7 +635,7 @@ dependencies = [ "itertools", "pulldown-cmark", "quine-mc_cluskey", - "regex-syntax", + "regex-syntax 0.7.1", "rustc-semver", "semver", "serde", @@ -723,6 +729,7 @@ dependencies = [ name = "compiletest" version = "0.0.0" dependencies = [ + "anyhow", "build_helper", "colored", "diff", @@ -854,7 +861,7 @@ dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset", + "memoffset 0.7.1", "scopeguard", ] @@ -1242,6 +1249,16 @@ dependencies = [ ] [[package]] +name = "field-offset" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3cf3a800ff6e860c863ca6d4b16fd999db8b752819c1606884047b73e468535" +dependencies = [ + "memoffset 0.8.0", + "rustc_version", +] + +[[package]] name = "filetime" version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2190,6 +2207,15 @@ dependencies = [ [[package]] name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" @@ -2198,6 +2224,15 @@ dependencies = [ ] [[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] name = "mime" version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -2336,13 +2371,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8d864c91689fdc196779b98dba0aceac6118594c2df6ee5d943eb6a8df4d107a" dependencies = [ "compiler_builtins", + "memchr", + "rustc-std-workspace-alloc", + "rustc-std-workspace-core", +] + +[[package]] +name = "object" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" +dependencies = [ "crc32fast", "flate2", "hashbrown 0.13.1", "indexmap", "memchr", - "rustc-std-workspace-alloc", - "rustc-std-workspace-core", + "ruzstd", ] [[package]] @@ -2667,9 +2712,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" [[package]] name = "proc-macro2" -version = "1.0.53" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] @@ -2837,7 +2882,7 @@ checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" dependencies = [ "aho-corasick", "memchr", - "regex-syntax", + "regex-syntax 0.6.26", ] [[package]] @@ -2846,7 +2891,7 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" dependencies = [ - "regex-syntax", + "regex-syntax 0.6.26", ] [[package]] @@ -2865,6 +2910,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" [[package]] +name = "regex-syntax" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" + +[[package]] name = "remote-test-client" version = "0.1.0" @@ -3194,7 +3245,7 @@ dependencies = [ "cstr", "libc", "measureme", - "object", + "object 0.31.1", "rustc-demangle", "rustc_ast", "rustc_attr", @@ -3230,7 +3281,7 @@ dependencies = [ "itertools", "jobserver", "libc", - "object", + "object 0.31.1", "pathdiff", "regex", "rustc_arena", @@ -3306,6 +3357,7 @@ dependencies = [ "rustc-hash", "rustc-rayon", "rustc-rayon-core", + "rustc_arena", "rustc_graphviz", "rustc_index", "rustc_macros", @@ -3781,6 +3833,7 @@ dependencies = [ "chalk-ir", "derive_more", "either", + "field-offset", "gsgdt", "measureme", "polonius-engine", @@ -3995,7 +4048,9 @@ dependencies = [ name = "rustc_query_impl" version = "0.0.0" dependencies = [ + "field-offset", "measureme", + "memoffset 0.6.5", "rustc-rayon-core", "rustc_ast", "rustc_data_structures", @@ -4386,6 +4441,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" [[package]] +name = "ruzstd" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a15e661f0f9dac21f3494fe5d23a6338c0ac116a2d22c2b63010acd89467ffe" +dependencies = [ + "byteorder", + "thiserror", + "twox-hash", +] + +[[package]] name = "ryu" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -4445,18 +4511,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c04e8343c3daeec41f58990b9d77068df31209f2af111e059e9fe9646693065" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.159" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c614d17805b093df4b147b51339e7e44bf05ef59fba1e45d83500bcfb4d8585" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", @@ -4621,7 +4687,7 @@ dependencies = [ "hermit-abi 0.3.0", "libc", "miniz_oxide", - "object", + "object 0.30.1", "panic_abort", "panic_unwind", "profiler_builtins", @@ -4893,13 +4959,13 @@ dependencies = [ [[package]] name = "thorin-dwp" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da8fbf660a019b6bf11ea95762041464aa9099cc293b6a66d77cea5107619671" +checksum = "98c040e1340b889d4180c64e1d787efa9c32cb1617757e101480b61238b0d927" dependencies = [ "gimli 0.26.2", "hashbrown 0.12.3", - "object", + "object 0.31.1", "tracing", ] @@ -5122,9 +5188,9 @@ checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" [[package]] name = "ui_test" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95033b0e41b8018013d99a6f1486c1ae5bd080378ced60c5f797e93842423b33" +checksum = "191a442639ea102fa62671026047e51d574bfda44b7fdf32151d7314624c1cd2" dependencies = [ "bstr 1.3.0", "cargo-platform", diff --git a/RELEASES.md b/RELEASES.md index e72905c15bd..85266a17550 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1481,7 +1481,7 @@ and related tools. [is_power_of_two_usize]: https://doc.rust-lang.org/stable/core/num/struct.NonZeroUsize.html#method.is_power_of_two [stdarch/1266]: https://github.com/rust-lang/stdarch/pull/1266 -Version 1.58.1 (2022-01-19) +Version 1.58.1 (2022-01-20) =========================== * Fix race condition in `std::fs::remove_dir_all` ([CVE-2022-21658]) diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs index 3d97d9b4895..f11c1c77f9c 100644 --- a/compiler/rustc_abi/src/layout.rs +++ b/compiler/rustc_abi/src/layout.rs @@ -12,7 +12,7 @@ use tracing::debug; pub trait LayoutCalculator { type TargetDataLayoutRef: Borrow<TargetDataLayout>; - fn delay_bug(&self, txt: &str); + fn delay_bug(&self, txt: String); fn current_data_layout(&self) -> Self::TargetDataLayoutRef; fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS { @@ -969,7 +969,7 @@ fn univariant( for &i in &inverse_memory_index { let field = &fields[i]; if !sized { - this.delay_bug(&format!( + this.delay_bug(format!( "univariant: field #{} comes after unsized field", offsets.len(), )); diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs index f0a6a5e0725..db296aa44db 100644 --- a/compiler/rustc_ast/src/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -48,14 +48,15 @@ pub enum TokenTree { Delimited(DelimSpan, Delimiter, TokenStream), } -// Ensure all fields of `TokenTree` is `Send` and `Sync`. +// Ensure all fields of `TokenTree` are `DynSend` and `DynSync`. #[cfg(parallel_compiler)] fn _dummy() where - Token: Send + Sync, - DelimSpan: Send + Sync, - Delimiter: Send + Sync, - TokenStream: Send + Sync, + Token: sync::DynSend + sync::DynSync, + Spacing: sync::DynSend + sync::DynSync, + DelimSpan: sync::DynSend + sync::DynSync, + Delimiter: sync::DynSend + sync::DynSync, + TokenStream: sync::DynSend + sync::DynSync, { } @@ -118,7 +119,7 @@ where } } -pub trait ToAttrTokenStream: sync::Send + sync::Sync { +pub trait ToAttrTokenStream: sync::DynSend + sync::DynSync { fn to_attr_token_stream(&self) -> AttrTokenStream; } @@ -550,6 +551,10 @@ impl TokenStream { vec_mut.extend(stream_iter); } } + + pub fn chunks(&self, chunk_size: usize) -> core::slice::Chunks<'_, TokenTree> { + self.0.chunks(chunk_size) + } } /// By-reference iterator over a [`TokenStream`], that produces `&TokenTree` diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index 3d154a93fb2..08ee3761bac 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -305,7 +305,10 @@ impl<'hir> LoweringContext<'_, 'hir> { ); this.arena.alloc(this.ty(span, hir::TyKind::Err(guar))) } - Some(ty) => this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy), + Some(ty) => this.lower_ty( + ty, + &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false }, + ), }, ); hir::ItemKind::TyAlias(ty, generics) @@ -852,7 +855,10 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ImplItemKind::Type(ty) } Some(ty) => { - let ty = this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy); + let ty = this.lower_ty( + ty, + &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true }, + ); hir::ImplItemKind::Type(ty) } }, diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 1fd7cc66470..211f5cb0a2a 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -58,7 +58,7 @@ use rustc_errors::{ use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; -use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID}; +use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::DefPathData; use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate}; use rustc_index::{Idx, IndexSlice, IndexVec}; @@ -247,7 +247,7 @@ enum ImplTraitContext { in_trait: bool, }, /// Impl trait in type aliases. - TypeAliasesOpaqueTy, + TypeAliasesOpaqueTy { in_assoc_ty: bool }, /// `impl Trait` is unstably accepted in this position. FeatureGated(ImplTraitPosition, Symbol), /// `impl Trait` is not accepted in this position. @@ -435,6 +435,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> { // Queries that borrow `resolver_for_lowering`. tcx.ensure_with_value().output_filenames(()); tcx.ensure_with_value().early_lint_checks(()); + tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE); let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal(); let ast_index = index_crate(&resolver.node_id_to_def_id, &krate); @@ -1407,14 +1408,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { *in_trait, itctx, ), - ImplTraitContext::TypeAliasesOpaqueTy => self.lower_opaque_impl_trait( - span, - hir::OpaqueTyOrigin::TyAlias, - *def_node_id, - bounds, - false, - itctx, - ), + &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self + .lower_opaque_impl_trait( + span, + hir::OpaqueTyOrigin::TyAlias { in_assoc_ty }, + *def_node_id, + bounds, + false, + itctx, + ), ImplTraitContext::Universal => { let span = t.span; self.create_def( @@ -1534,13 +1536,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // If this came from a TAIT (as opposed to a function that returns an RPIT), we only want // to capture the lifetimes that appear in the bounds. So visit the bounds to find out // exactly which ones those are. - let lifetimes_to_remap = if origin == hir::OpaqueTyOrigin::TyAlias { - // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters - Vec::new() - } else { - // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example, - // we only keep the lifetimes that appear in the `impl Debug` itself: - lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds) + let lifetimes_to_remap = match origin { + hir::OpaqueTyOrigin::TyAlias { .. } => { + // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters + Vec::new() + } + hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => { + // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example, + // we only keep the lifetimes that appear in the `impl Debug` itself: + lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds) + } }; debug!(?lifetimes_to_remap); diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index 2a3092d3c7b..372a58857f3 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -23,8 +23,7 @@ use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause}; pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION"; pub fn rust_version_symbol() -> Symbol { - let version = option_env!("CFG_VERSION").unwrap_or("<current>"); - let version = version.split(' ').next().unwrap(); + let version = option_env!("CFG_RELEASE").unwrap_or("<current>"); Symbol::intern(&version) } diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs index 94939c7e4cd..167f245361a 100644 --- a/compiler/rustc_borrowck/src/dataflow.rs +++ b/compiler/rustc_borrowck/src/dataflow.rs @@ -328,7 +328,7 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain { // bottom = nothing is reserved or activated yet; - BitSet::new_empty(self.borrow_set.len() * 2) + BitSet::new_empty(self.borrow_set.len()) } fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 315303b25fe..eb25d454339 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -35,7 +35,7 @@ use rustc_middle::mir::{ use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind}; use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind}; use rustc_middle::mir::{ProjectionElem, Promoted, Rvalue, Statement, StatementKind}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt}; use rustc_session::lint::builtin::UNUSED_MUT; use rustc_span::{Span, Symbol}; diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index a4394ddc01c..b6ccf924a5c 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -430,7 +430,7 @@ pub(super) fn dump_annotation<'tcx>( fn for_each_region_constraint<'tcx>( tcx: TyCtxt<'tcx>, closure_region_requirements: &ClosureRegionRequirements<'tcx>, - with_msg: &mut dyn FnMut(&str) -> io::Result<()>, + with_msg: &mut dyn FnMut(String) -> io::Result<()>, ) -> io::Result<()> { for req in &closure_region_requirements.outlives_requirements { let subject = match req.subject { @@ -439,7 +439,7 @@ fn for_each_region_constraint<'tcx>( format!("{:?}", ty.instantiate(tcx, |vid| tcx.mk_re_var(vid))) } }; - with_msg(&format!("where {}: {:?}", subject, req.outlived_free_region,))?; + with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?; } Ok(()) } diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs index 4970ece5e7d..309f23d9226 100644 --- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs +++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs @@ -265,7 +265,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> { // Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs` // on stable and we'd break that. - let OpaqueTyOrigin::TyAlias = origin else { + let OpaqueTyOrigin::TyAlias { .. } = origin else { return definition_ty; }; let def_id = opaque_type_key.def_id; @@ -360,7 +360,7 @@ fn check_opaque_type_parameter_valid( // which would error here on all of the `'static` args. OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()), // Check these - OpaqueTyOrigin::TyAlias => {} + OpaqueTyOrigin::TyAlias { .. } => {} } let opaque_generics = tcx.generics_of(opaque_type_key.def_id); let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default(); diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 33b24b68f7c..fa4bc926f27 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -71,7 +71,7 @@ macro_rules! span_mirbug { $crate::type_check::mirbug( $context.tcx(), $context.last_span, - &format!( + format!( "broken MIR in {:?} ({:?}): {}", $context.body().source.def_id(), $elem, @@ -274,7 +274,7 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) { } #[track_caller] -fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: &str) { +fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: String) { // We sometimes see MIR failures (notably predicate failures) due to // the fact that we check rvalue sized predicates here. So use `delay_span_bug` // to avoid reporting bugs in those cases. diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index bb059a120df..5217e317adf 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -550,7 +550,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl if !parser.errors.is_empty() { let err = parser.errors.remove(0); let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); - let msg = &format!("invalid asm template string: {}", err.description); + let msg = format!("invalid asm template string: {}", err.description); let mut e = ecx.struct_span_err(err_sp, msg); e.span_label(err_sp, err.label + " in asm template string"); if let Some(note) = err.note { @@ -585,7 +585,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl || args.reg_args.contains(idx) { let msg = format!("invalid reference to argument at index {}", idx); - let mut err = ecx.struct_span_err(span, &msg); + let mut err = ecx.struct_span_err(span, msg); err.span_label(span, "from here"); let positional_args = args.operands.len() @@ -638,7 +638,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl ecx.struct_span_err( template_span .from_inner(InnerSpan::new(span.start, span.end)), - &msg, + msg, ) .emit(); None diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs index 750f1fe121f..ed91cea4ae2 100644 --- a/compiler/rustc_builtin_macros/src/cfg_eval.rs +++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs @@ -166,7 +166,9 @@ impl CfgEval<'_, '_> { )) }, Annotatable::Stmt(_) => |parser| { - Ok(Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes)?.unwrap()))) + Ok(Annotatable::Stmt(P(parser + .parse_stmt_without_recovery(false, ForceCollect::Yes)? + .unwrap()))) }, Annotatable::Expr(_) => { |parser| Ok(Annotatable::Expr(parser.parse_expr_force_collect()?)) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index 0481a118906..2c8e6f99c67 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -27,3 +27,26 @@ pub fn expand_deriving_copy( trait_def.expand(cx, mitem, item, push); } + +pub fn expand_deriving_const_param_ty( + cx: &mut ExtCtxt<'_>, + span: Span, + mitem: &MetaItem, + item: &Annotatable, + push: &mut dyn FnMut(Annotatable), + is_const: bool, +) { + let trait_def = TraitDef { + span, + path: path_std!(marker::ConstParamTy), + skip_path_as_bound: false, + needs_copy_as_bound_if_packed: false, + additional_bounds: Vec::new(), + supports_unions: false, + methods: Vec::new(), + associated_types: Vec::new(), + is_const, + }; + + trait_def.expand(cx, mitem, item, push); +} diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs index dfee2d3ce77..9883563746e 100644 --- a/compiler/rustc_builtin_macros/src/deriving/clone.rs +++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs @@ -145,7 +145,7 @@ fn cs_clone_simple( } _ => cx.span_bug( trait_span, - &format!("unexpected substructure in simple `derive({})`", name), + format!("unexpected substructure in simple `derive({})`", name), ), } } @@ -179,10 +179,10 @@ fn cs_clone( vdata = &variant.data; } EnumTag(..) | AllFieldlessEnum(..) => { - cx.span_bug(trait_span, &format!("enum tags in `derive({})`", name,)) + cx.span_bug(trait_span, format!("enum tags in `derive({})`", name,)) } StaticEnum(..) | StaticStruct(..) => { - cx.span_bug(trait_span, &format!("associated function in `derive({})`", name)) + cx.span_bug(trait_span, format!("associated function in `derive({})`", name)) } } @@ -194,7 +194,7 @@ fn cs_clone( let Some(ident) = field.name else { cx.span_bug( trait_span, - &format!("unnamed field in normal struct in `derive({})`", name,), + format!("unnamed field in normal struct in `derive({})`", name,), ); }; let call = subcall(cx, field); diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index caced3d6447..4ba09335cb7 100644 --- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -1591,7 +1591,7 @@ impl<'a> TraitDef<'a> { BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE, sp, ast::CRATE_NODE_ID, - &format!( + format!( "{} slice in a packed struct that derives a built-in trait", ty ), diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 58c972738c4..8f64e332861 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -63,7 +63,8 @@ pub fn expand_env<'cx>( Some(exprs) => exprs.into_iter(), }; - let Some((var, _style)) = expr_to_string(cx, exprs.next().unwrap(), "expected string literal") else { + let var_expr = exprs.next().unwrap(); + let Some((var, _)) = expr_to_string(cx, var_expr.clone(), "expected string literal") else { return DummyResult::any(sp); }; @@ -71,7 +72,7 @@ pub fn expand_env<'cx>( None => None, Some(second) => match expr_to_string(cx, second, "expected string literal") { None => return DummyResult::any(sp), - Some((s, _style)) => Some(s), + Some((s, _)) => Some(s), }, }; @@ -80,10 +81,15 @@ pub fn expand_env<'cx>( cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { + // Use the string literal in the code in the diagnostic to avoid confusing diagnostics, + // e.g. when the literal contains escape sequences. + let ast::ExprKind::Lit(ast::token::Lit { kind: ast::token::LitKind::Str, symbol: original_var, ..}) = &var_expr.kind else { + unreachable!("`expr_to_string` ensures this is a string lit") + }; cx.emit_err(errors::EnvNotDefined { span: sp, msg: custom_msg, - var, + var: *original_var, help: custom_msg.is_none().then(|| help_for_missing_env_var(var.as_str())), }); return DummyResult::any(sp); diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index adc12ec84f5..c59a733c055 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -814,7 +814,7 @@ fn report_invalid_references( }; e = ecx.struct_span_err( span, - &format!("invalid reference to positional {} ({})", arg_list, num_args_desc), + format!("invalid reference to positional {} ({})", arg_list, num_args_desc), ); e.note("positional arguments are zero-based"); } diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs index bd9e903b6ba..bd5356575ca 100644 --- a/compiler/rustc_builtin_macros/src/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -562,15 +562,13 @@ pub(crate) mod printf { } if let Type = state { - drop(c); type_ = at.slice_between(next).unwrap(); // Don't use `move_to!` here, as we *can* be at the end of the input. at = next; } - drop(c); - drop(next); + let _ = c; // to avoid never used value end = at; let position = InnerSpan::new(start.at, end.at); diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 4e5edb4d6b1..ebf1448f55c 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -115,6 +115,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { register_derive! { Clone: clone::expand_deriving_clone, Copy: bounds::expand_deriving_copy, + ConstParamTy: bounds::expand_deriving_const_param_ty, Debug: debug::expand_deriving_debug, Default: default::expand_deriving_default, Eq: eq::expand_deriving_eq, diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index b8a24f1102d..e613b904d2e 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -188,12 +188,12 @@ pub fn expand_include_str( base::MacEager::expr(cx.expr_str(sp, interned_src)) } Err(_) => { - cx.span_err(sp, &format!("{} wasn't a utf-8 file", file.display())); + cx.span_err(sp, format!("{} wasn't a utf-8 file", file.display())); DummyResult::any(sp) } }, Err(e) => { - cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e)); + cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e)); DummyResult::any(sp) } } @@ -221,7 +221,7 @@ pub fn expand_include_bytes( base::MacEager::expr(expr) } Err(e) => { - cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e)); + cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e)); DummyResult::any(sp) } } diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index e9dbea1be67..25fd5ca3ae8 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -966,11 +966,7 @@ fn codegen_panic_inner<'tcx>( args: &[Value], span: Span, ) { - let def_id = fx - .tcx - .lang_items() - .require(lang_item) - .unwrap_or_else(|e| fx.tcx.sess.span_fatal(span, e.to_string())); + let def_id = fx.tcx.require_lang_item(lang_item, Some(span)); let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx); let symbol_name = fx.tcx.symbol_name(instance).name; diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs index 27e21183c55..1007b33eca4 100644 --- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs +++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs @@ -227,7 +227,7 @@ pub(crate) fn write_ir_file( // Using early_warn as no Session is available here rustc_session::early_warn( rustc_session::config::ErrorOutputType::default(), - &format!("error writing ir file: {}", err), + format!("error writing ir file: {}", err), ); } } diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 1cabb05de97..442ce0ea542 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -80,8 +80,8 @@ use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMes use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_middle::ty::query::Providers; use rustc_session::config::{Lto, OptLevel, OutputFilenames}; use rustc_session::Session; use rustc_span::Symbol; diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml index 5e750d91b82..ad51f2d0958 100644 --- a/compiler/rustc_codegen_llvm/Cargo.toml +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -11,7 +11,7 @@ bitflags = "1.0" cstr = "0.2" libc = "0.2" measureme = "10.0.0" -object = { version = "0.30.1", default-features = false, features = [ +object = { version = "0.31.1", default-features = false, features = [ "std", "read", ] } diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index d2e01708a37..604f68eb6a4 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -25,7 +25,6 @@ use std::fs::File; use std::io; use std::iter; use std::path::Path; -use std::ptr; use std::slice; use std::sync::Arc; @@ -709,17 +708,6 @@ pub unsafe fn optimize_thin_module( let llmod = module.module_llvm.llmod(); save_temp_bitcode(cgcx, &module, "thin-lto-input"); - // Before we do much else find the "main" `DICompileUnit` that we'll be - // using below. If we find more than one though then rustc has changed - // in a way we're not ready for, so generate an ICE by returning - // an error. - let mut cu1 = ptr::null_mut(); - let mut cu2 = ptr::null_mut(); - llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2); - if !cu2.is_null() { - return Err(write::llvm_err(&diag_handler, LlvmError::MultipleSourceDiCompileUnit)); - } - // Up next comes the per-module local analyses that we do for Thin LTO. // Each of these functions is basically copied from the LLVM // implementation and then tailored to suit this implementation. Ideally @@ -766,43 +754,6 @@ pub unsafe fn optimize_thin_module( save_temp_bitcode(cgcx, &module, "thin-lto-after-import"); } - // Ok now this is a bit unfortunate. This is also something you won't - // find upstream in LLVM's ThinLTO passes! This is a hack for now to - // work around bugs in LLVM. - // - // First discovered in #45511 it was found that as part of ThinLTO - // importing passes LLVM will import `DICompileUnit` metadata - // information across modules. This means that we'll be working with one - // LLVM module that has multiple `DICompileUnit` instances in it (a - // bunch of `llvm.dbg.cu` members). Unfortunately there's a number of - // bugs in LLVM's backend which generates invalid DWARF in a situation - // like this: - // - // https://bugs.llvm.org/show_bug.cgi?id=35212 - // https://bugs.llvm.org/show_bug.cgi?id=35562 - // - // While the first bug there is fixed the second ended up causing #46346 - // which was basically a resurgence of #45511 after LLVM's bug 35212 was - // fixed. - // - // This function below is a huge hack around this problem. The function - // below is defined in `PassWrapper.cpp` and will basically "merge" - // all `DICompileUnit` instances in a module. Basically it'll take all - // the objects, rewrite all pointers of `DISubprogram` to point to the - // first `DICompileUnit`, and then delete all the other units. - // - // This is probably mangling to the debug info slightly (but hopefully - // not too much) but for now at least gets LLVM to emit valid DWARF (or - // so it appears). Hopefully we can remove this once upstream bugs are - // fixed in LLVM. - { - let _timer = cgcx - .prof - .generic_activity_with_arg("LLVM_thin_lto_patch_debuginfo", thin_module.name()); - llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1); - save_temp_bitcode(cgcx, &module, "thin-lto-after-patch"); - } - // Alright now that we've done everything related to the ThinLTO // analysis it's time to run some optimizations! Here we use the same // `run_pass_manager` as the "fat" LTO above except that we tell it to diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs index aaf5dbd9930..37f30917609 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs @@ -9,10 +9,9 @@ use rustc_ast::attr; use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive; use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_middle::bug; +use rustc_middle::{bug, middle::debugger_visualizer::DebuggerVisualizerType}; use rustc_session::config::{CrateType, DebugInfo}; use rustc_span::symbol::sym; -use rustc_span::DebuggerVisualizerType; /// Inserts a side-effect free instruction sequence that makes sure that the /// .debug_gdb_scripts global is referenced, so it isn't removed by the linker. diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 25fe3cb265d..bd2fba12602 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -806,8 +806,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>( name_in_debuginfo.push(codegen_unit_name); debug!("build_compile_unit_di_node: {:?}", name_in_debuginfo); - let rustc_producer = - format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"),); + let rustc_producer = format!("rustc version {}", tcx.sess.cfg_version); // FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice. let producer = format!("clang LLVM ({})", rustc_producer); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 8305a0a4c28..6a86237d79e 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -37,7 +37,7 @@ use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, FatalError, Handler, Subd use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest}; use rustc_session::Session; diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index aefd5b2a13c..de93a64c0d6 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -2484,12 +2484,6 @@ extern "C" { len: usize, out_len: &mut usize, ) -> *const u8; - pub fn LLVMRustThinLTOGetDICompileUnit( - M: &Module, - CU1: &mut *mut c_void, - CU2: &mut *mut c_void, - ); - pub fn LLVMRustThinLTOPatchDICompileUnit(M: &Module, CU: *mut c_void); pub fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>; pub fn LLVMRustLinkerAdd( diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index 2fbdab9f8ce..994addf12eb 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -155,12 +155,6 @@ pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2] ("x86", "rdrand") => smallvec!["rdrnd"], ("x86", "bmi1") => smallvec!["bmi"], ("x86", "cmpxchg16b") => smallvec!["cx16"], - // FIXME: These aliases are misleading, and should be removed before avx512_target_feature is - // stabilized. They must remain until std::arch switches off them. - // rust#100752 - ("x86", "avx512vaes") => smallvec!["vaes"], - ("x86", "avx512gfni") => smallvec!["gfni"], - ("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"], ("aarch64", "rcpc2") => smallvec!["rcpc-immo"], ("aarch64", "dpb") => smallvec!["ccpp"], ("aarch64", "dpb2") => smallvec!["ccdp"], diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 02be88df103..0ac12d32be5 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -14,7 +14,7 @@ itertools = "0.10.1" tracing = "0.1" jobserver = "0.1.22" tempfile = "3.2" -thorin-dwp = "0.4" +thorin-dwp = "0.6" pathdiff = "0.2.0" serde_json = "1.0.59" snap = "1" @@ -46,7 +46,7 @@ rustc_session = { path = "../rustc_session" } libc = "0.2.50" [dependencies.object] -version = "0.30.1" +version = "0.31.1" default-features = false features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"] diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index ea06cb02d8b..8a00c42a0e8 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -9,6 +9,7 @@ use rustc_fs_util::fix_windows_verbatim_for_gcc; use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_metadata::find_native_static_library; use rustc_metadata::fs::{emit_wrapper_file, METADATA_FILENAME}; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip}; @@ -21,7 +22,6 @@ use rustc_session::utils::NativeLibKind; /// need out of the shared crate context before we get rid of it. use rustc_session::{filesearch, Session}; use rustc_span::symbol::Symbol; -use rustc_span::DebuggerVisualizerFile; use rustc_target::spec::crt_objects::{CrtObjects, LinkSelfContainedDefault}; use rustc_target::spec::{Cc, LinkOutputKind, LinkerFlavor, LinkerFlavorCli, Lld, PanicStrategy}; use rustc_target::spec::{RelocModel, RelroLevel, SanitizerSet, SplitDebuginfo}; @@ -574,6 +574,8 @@ fn link_staticlib<'a>( } } + all_native_libs.extend_from_slice(&codegen_results.crate_info.used_libraries); + if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) { print_native_static_libs(sess, &all_native_libs, &all_rust_dylibs); } diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index 8968133bac5..8bf84772f08 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -14,8 +14,7 @@ use snap::write::FrameEncoder; use object::elf::NT_GNU_PROPERTY_TYPE_0; use rustc_data_structures::memmap::Mmap; -use rustc_data_structures::owned_slice::try_slice_owned; -use rustc_data_structures::sync::MetadataRef; +use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice}; use rustc_metadata::fs::METADATA_FILENAME; use rustc_metadata::EncodedMetadata; use rustc_session::cstore::MetadataLoader; @@ -39,7 +38,7 @@ pub struct DefaultMetadataLoader; fn load_metadata_with( path: &Path, f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>, -) -> Result<MetadataRef, String> { +) -> Result<OwnedSlice, String> { let file = File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?; @@ -49,7 +48,7 @@ fn load_metadata_with( } impl MetadataLoader for DefaultMetadataLoader { - fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> { + fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> { load_metadata_with(path, |data| { let archive = object::read::archive::ArchiveFile::parse(&*data) .map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?; @@ -69,7 +68,7 @@ impl MetadataLoader for DefaultMetadataLoader { }) } - fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> { + fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> { load_metadata_with(path, |data| search_for_section(path, data, ".rustc")) } } diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index 8f2f829c17c..14460efc1b0 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -11,7 +11,7 @@ use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }; use rustc_middle::query::LocalCrate; -use rustc_middle::ty::query::{ExternProviders, Providers}; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef}; use rustc_middle::ty::Instance; use rustc_middle::ty::{self, SymbolName, TyCtxt}; diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index ae45ae9d802..15c7847155d 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -17,28 +17,25 @@ use rustc_ast::expand::allocator::AllocatorKind; use rustc_attr as attr; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry}; - -use rustc_data_structures::sync::par_iter; -#[cfg(parallel_compiler)] -use rustc_data_structures::sync::ParallelIterator; +use rustc_data_structures::sync::par_map; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::lang_items::LangItem; use rustc_metadata::EncodedMetadata; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; +use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_middle::middle::exported_symbols; use rustc_middle::middle::exported_symbols::SymbolExportKind; use rustc_middle::middle::lang_items; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; +use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Symbol; -use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType}; use rustc_target::abi::{Align, FIRST_VARIANT}; use std::collections::BTreeSet; @@ -689,7 +686,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>( // This likely is a temporary measure. Once we don't have to support the // non-parallel compiler anymore, we can compile CGUs end-to-end in // parallel and get rid of the complicated scheduling logic. - let mut pre_compiled_cgus = if cfg!(parallel_compiler) { + let mut pre_compiled_cgus = if tcx.sess.threads() > 1 { tcx.sess.time("compile_first_CGU_batch", || { // Try to find one CGU to compile per thread. let cgus: Vec<_> = cgu_reuse @@ -702,12 +699,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>( // Compile the found CGUs in parallel. let start_time = Instant::now(); - let pre_compiled_cgus = par_iter(cgus) - .map(|(i, _)| { - let module = backend.compile_codegen_unit(tcx, codegen_units[i].name()); - (i, module) - }) - .collect(); + let pre_compiled_cgus = par_map(cgus, |(i, _)| { + let module = backend.compile_codegen_unit(tcx, codegen_units[i].name()); + (i, module) + }); total_codegen_time += start_time.elapsed(); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index 8dae5dab429..d6c23012762 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -7,7 +7,7 @@ use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem}; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::mono::Linkage; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self as ty, TyCtxt}; use rustc_session::{lint, parse::feature_err}; use rustc_span::symbol::Ident; diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index c3cc17c255b..31854c7f4c4 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -28,16 +28,17 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir::def_id::CrateNum; use rustc_middle::dep_graph::WorkProduct; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Dependencies; use rustc_middle::middle::exported_symbols::SymbolExportKind; -use rustc_middle::ty::query::{ExternProviders, Providers}; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_serialize::opaque::{FileEncoder, MemDecoder}; use rustc_serialize::{Decodable, Decoder, Encodable, Encoder}; use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT}; use rustc_session::cstore::{self, CrateSource}; use rustc_session::utils::NativeLibKind; +use rustc_session::Session; use rustc_span::symbol::Symbol; -use rustc_span::DebuggerVisualizerFile; use std::collections::BTreeSet; use std::io; use std::path::{Path, PathBuf}; @@ -175,11 +176,11 @@ pub struct CodegenResults { pub crate_info: CrateInfo, } -pub enum CodegenErrors<'a> { +pub enum CodegenErrors { WrongFileType, EmptyVersionNumber, EncodingVersionMismatch { version_array: String, rlink_version: u32 }, - RustcVersionMismatch { rustc_version: String, current_version: &'a str }, + RustcVersionMismatch { rustc_version: String }, } pub fn provide(providers: &mut Providers) { @@ -213,10 +214,9 @@ pub fn looks_like_rust_object_file(filename: &str) -> bool { const RLINK_VERSION: u32 = 1; const RLINK_MAGIC: &[u8] = b"rustlink"; -const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION"); - impl CodegenResults { pub fn serialize_rlink( + sess: &Session, rlink_file: &Path, codegen_results: &CodegenResults, ) -> Result<usize, io::Error> { @@ -225,12 +225,12 @@ impl CodegenResults { // `emit_raw_bytes` is used to make sure that the version representation does not depend on // Encoder's inner representation of `u32`. encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes()); - encoder.emit_str(RUSTC_VERSION.unwrap()); + encoder.emit_str(sess.cfg_version); Encodable::encode(codegen_results, &mut encoder); encoder.finish() } - pub fn deserialize_rlink<'a>(data: Vec<u8>) -> Result<Self, CodegenErrors<'a>> { + pub fn deserialize_rlink(sess: &Session, data: Vec<u8>) -> Result<Self, CodegenErrors> { // The Decodable machinery is not used here because it panics if the input data is invalid // and because its internal representation may change. if !data.starts_with(RLINK_MAGIC) { @@ -252,11 +252,9 @@ impl CodegenResults { let mut decoder = MemDecoder::new(&data[4..], 0); let rustc_version = decoder.read_str(); - let current_version = RUSTC_VERSION.unwrap(); - if rustc_version != current_version { + if rustc_version != sess.cfg_version { return Err(CodegenErrors::RustcVersionMismatch { rustc_version: rustc_version.to_string(), - current_version, }); } diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs index 4e5e2dd5d50..bba2800fb05 100644 --- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs +++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_session::config::DebugInfo; use rustc_span::symbol::{kw, Symbol}; use rustc_span::{BytePos, Span}; -use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx}; +use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx}; use super::operand::{OperandRef, OperandValue}; use super::place::PlaceRef; @@ -41,6 +41,9 @@ pub struct PerLocalVarDebugInfo<'tcx, D> { /// `.place.projection` from `mir::VarDebugInfo`. pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>, + + /// `references` from `mir::VarDebugInfo`. + pub references: u8, } #[derive(Clone, Copy, Debug)] @@ -80,6 +83,7 @@ trait DebugInfoOffsetLocation<'tcx, Bx> { fn deref(&self, bx: &mut Bx) -> Self; fn layout(&self) -> TyAndLayout<'tcx>; fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self; + fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self; fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self; } @@ -98,6 +102,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> PlaceRef::project_field(*self, bx, field.index()) } + fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self { + let lloffset = bx.cx().const_usize(offset); + self.project_index(bx, lloffset) + } + fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self { self.project_downcast(bx, variant) } @@ -120,6 +129,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx> self.field(bx.cx(), field.index()) } + fn project_constant_index(&self, bx: &mut Bx, index: u64) -> Self { + self.field(bx.cx(), index as usize) + } + fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self { self.for_variant(bx.cx(), variant) } @@ -165,6 +178,18 @@ fn calculate_debuginfo_offset< mir::ProjectionElem::Downcast(_, variant) => { place = place.downcast(bx, variant); } + mir::ProjectionElem::ConstantIndex { + offset: index, + min_length: _, + from_end: false, + } => { + let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset); + let FieldsShape::Array { stride, count: _ } = place.layout().fields else { + span_bug!(var.source_info.span, "ConstantIndex on non-array type {:?}", place.layout()) + }; + *offset += stride * index; + place = place.project_constant_index(bx, index); + } _ => { // Sanity check for `can_use_in_debuginfo`. debug_assert!(!elem.can_use_in_debuginfo()); @@ -293,6 +318,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dbg_var, fragment: None, projection: ty::List::empty(), + references: 0, }) } } else { @@ -358,55 +384,74 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let vars = vars.iter().cloned().chain(fallback_var); for var in vars { - let Some(dbg_var) = var.dbg_var else { continue }; - let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue }; - - let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } = - calculate_debuginfo_offset(bx, local, &var, base.layout); - - // When targeting MSVC, create extra allocas for arguments instead of pointing multiple - // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records - // not DWARF and LLVM doesn't support translating the resulting - // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView. - // Creating extra allocas on the stack makes the resulting debug info simple enough - // that LLVM can generate correct CodeView records and thus the values appear in the - // debugger. (#83709) - let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc - && self.mir.local_kind(local) == mir::LocalKind::Arg - // LLVM can handle simple things but anything more complex than just a direct - // offset or one indirect offset of 0 is too complex for it to generate CV records - // correctly. - && (direct_offset != Size::ZERO - || !matches!(&indirect_offsets[..], [Size::ZERO] | [])); - - if should_create_individual_allocas { - let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } = - calculate_debuginfo_offset(bx, local, &var, base); - - // Create a variable which will be a pointer to the actual value - let ptr_ty = bx - .tcx() - .mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty }); - let ptr_layout = bx.layout_of(ptr_ty); - let alloca = PlaceRef::alloca(bx, ptr_layout); - bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill")); - - // Write the pointer to the variable - bx.store(place.llval, alloca.llval, alloca.align); - - // Point the debug info to `*alloca` for the current variable - bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO], None); - } else { - bx.dbg_var_addr( - dbg_var, - dbg_loc, - base.llval, - direct_offset, - &indirect_offsets, - None, - ); + self.debug_introduce_local_as_var(bx, local, base, var); + } + } + + fn debug_introduce_local_as_var( + &self, + bx: &mut Bx, + local: mir::Local, + mut base: PlaceRef<'tcx, Bx::Value>, + var: PerLocalVarDebugInfo<'tcx, Bx::DIVariable>, + ) { + let Some(dbg_var) = var.dbg_var else { return }; + let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return }; + + let DebugInfoOffset { mut direct_offset, indirect_offsets, result: _ } = + calculate_debuginfo_offset(bx, local, &var, base.layout); + let mut indirect_offsets = &indirect_offsets[..]; + + // When targeting MSVC, create extra allocas for arguments instead of pointing multiple + // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records + // not DWARF and LLVM doesn't support translating the resulting + // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView. + // Creating extra allocas on the stack makes the resulting debug info simple enough + // that LLVM can generate correct CodeView records and thus the values appear in the + // debugger. (#83709) + let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc + && self.mir.local_kind(local) == mir::LocalKind::Arg + // LLVM can handle simple things but anything more complex than just a direct + // offset or one indirect offset of 0 is too complex for it to generate CV records + // correctly. + && (direct_offset != Size::ZERO || !matches!(indirect_offsets, [Size::ZERO] | [])); + + let create_alloca = |bx: &mut Bx, place: PlaceRef<'tcx, Bx::Value>, refcount| { + // Create a variable which will be a pointer to the actual value + let ptr_ty = bx + .tcx() + .mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty }); + let ptr_layout = bx.layout_of(ptr_ty); + let alloca = PlaceRef::alloca(bx, ptr_layout); + bx.set_var_name(alloca.llval, &format!("{}.ref{}.dbg.spill", var.name, refcount)); + + // Write the pointer to the variable + bx.store(place.llval, alloca.llval, alloca.align); + + // Point the debug info to `*alloca` for the current variable + alloca + }; + + if var.references > 0 { + base = calculate_debuginfo_offset(bx, local, &var, base).result; + + // Point the debug info to `&...&base == alloca` for the current variable + for refcount in 0..var.references { + base = create_alloca(bx, base, refcount); } + + direct_offset = Size::ZERO; + indirect_offsets = &[]; + } else if should_create_individual_allocas { + let place = calculate_debuginfo_offset(bx, local, &var, base).result; + + // Point the debug info to `*alloca` for the current variable + base = create_alloca(bx, place, 0); + direct_offset = Size::ZERO; + indirect_offsets = &[Size::ZERO]; } + + bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, indirect_offsets, None); } pub fn debug_introduce_locals(&self, bx: &mut Bx) { @@ -439,7 +484,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }; let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| { - let (var_ty, var_kind) = match var.value { + let (mut var_ty, var_kind) = match var.value { mir::VarDebugInfoContents::Place(place) => { let var_ty = self.monomorphized_place_ty(place.as_ref()); let var_kind = if let Some(arg_index) = var.argument_index @@ -476,6 +521,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } }; + for _ in 0..var.references { + var_ty = + bx.tcx().mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: var_ty }); + } + self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span) }); @@ -487,6 +537,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { dbg_var, fragment: None, projection: place.projection, + references: var.references, }); } mir::VarDebugInfoContents::Const(c) => { @@ -540,6 +591,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { Some(fragment_start..fragment_start + fragment_layout.size) }, projection: place.projection, + references: var.references, }); } } diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs index 9efbb34b515..2301c3ef13e 100644 --- a/compiler/rustc_codegen_ssa/src/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -402,8 +402,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> { indirect_dest: PlaceRef<'tcx, V>, ) { debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest); - let flags = MemFlags::empty(); - // `indirect_dest` must have `*mut T` type. We extract `T` out of it. let unsized_ty = indirect_dest .layout @@ -416,17 +414,23 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> { bug!("store_unsized called with a sized value") }; - // FIXME: choose an appropriate alignment, or use dynamic align somehow - let max_align = Align::from_bits(128).unwrap(); - let min_align = Align::from_bits(8).unwrap(); - - // Allocate an appropriate region on the stack, and copy the value into it - let (llsize, _) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra)); - let lldst = bx.byte_array_alloca(llsize, max_align); - bx.memcpy(lldst, max_align, llptr, min_align, llsize, flags); + // Allocate an appropriate region on the stack, and copy the value into it. Since alloca + // doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the + // pointer manually. + let (size, align) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra)); + let one = bx.const_usize(1); + let align_minus_1 = bx.sub(align, one); + let size_extra = bx.add(size, align_minus_1); + let min_align = Align::ONE; + let alloca = bx.byte_array_alloca(size_extra, min_align); + let address = bx.ptrtoint(alloca, bx.type_isize()); + let neg_address = bx.neg(address); + let offset = bx.and(neg_address, align_minus_1); + let dst = bx.inbounds_gep(bx.type_i8(), alloca, &[offset]); + bx.memcpy(dst, min_align, llptr, min_align, size, MemFlags::empty()); // Store the allocated region and the extra to the indirect place. - let indirect_operand = OperandValue::Pair(lldst, llextra); + let indirect_operand = OperandValue::Pair(dst, llextra); indirect_operand.store(bx, indirect_dest); } } diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index 1cfc4b933a8..c5976a65411 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -8,7 +8,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::def_id::LocalDefId; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_session::Session; @@ -173,16 +173,13 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("avx512dq", Some(sym::avx512_target_feature)), ("avx512er", Some(sym::avx512_target_feature)), ("avx512f", Some(sym::avx512_target_feature)), - ("avx512gfni", Some(sym::avx512_target_feature)), ("avx512ifma", Some(sym::avx512_target_feature)), ("avx512pf", Some(sym::avx512_target_feature)), - ("avx512vaes", Some(sym::avx512_target_feature)), ("avx512vbmi", Some(sym::avx512_target_feature)), ("avx512vbmi2", Some(sym::avx512_target_feature)), ("avx512vl", Some(sym::avx512_target_feature)), ("avx512vnni", Some(sym::avx512_target_feature)), ("avx512vp2intersect", Some(sym::avx512_target_feature)), - ("avx512vpclmulqdq", Some(sym::avx512_target_feature)), ("avx512vpopcntdq", Some(sym::avx512_target_feature)), ("bmi1", None), ("bmi2", None), @@ -253,6 +250,7 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[ ("f", Some(sym::riscv_target_feature)), ("m", Some(sym::riscv_target_feature)), ("relax", Some(sym::riscv_target_feature)), + ("unaligned-scalar-mem", Some(sym::riscv_target_feature)), ("v", Some(sym::riscv_target_feature)), ("zba", Some(sym::riscv_target_feature)), ("zbb", Some(sym::riscv_target_feature)), diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index 64bebe50ddb..d83bfc74082 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -1,3 +1,5 @@ +use std::any::Any; + use super::write::WriteBackendMethods; use super::CodegenObject; use crate::back::write::TargetMachineFactoryFn; @@ -5,11 +7,12 @@ use crate::{CodegenResults, ModuleCodegen}; use rustc_ast::expand::allocator::AllocatorKind; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::sync::{DynSend, DynSync}; use rustc_errors::ErrorGuaranteed; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout}; -use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::{Ty, TyCtxt}; use rustc_session::{ config::{self, OutputFilenames, PrintRequest}, @@ -20,10 +23,6 @@ use rustc_span::symbol::Symbol; use rustc_target::abi::call::FnAbi; use rustc_target::spec::Target; -pub use rustc_data_structures::sync::MetadataRef; - -use std::any::Any; - pub trait BackendTypes { type Value: CodegenObject; type Function: CodegenObject; @@ -117,7 +116,9 @@ pub trait CodegenBackend { ) -> Result<(), ErrorGuaranteed>; } -pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send + Sync { +pub trait ExtraBackendMethods: + CodegenBackend + WriteBackendMethods + Sized + Send + Sync + DynSend + DynSync +{ fn codegen_allocator<'tcx>( &self, tcx: TyCtxt<'tcx>, diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index cdef3fb2339..c591ff75ab8 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -3,7 +3,8 @@ use std::fmt; use rustc_errors::Diagnostic; use rustc_middle::mir::AssertKind; -use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt}; +use rustc_middle::query::TyCtxtAt; +use rustc_middle::ty::{layout::LayoutError, ConstInt}; use rustc_span::{Span, Symbol}; use super::InterpCx; @@ -169,14 +170,14 @@ impl<'tcx> ConstEvalErr<'tcx> { // See <https://github.com/rust-lang/rust/pull/63152>. let mut err = struct_error(tcx, &self.error.to_string()); self.decorate(&mut err, decorate); - ErrorHandled::Reported(err.emit()) + ErrorHandled::Reported(err.emit().into()) } _ => { // Report as hard error. let mut err = struct_error(tcx, message); err.span_label(self.span, self.error.to_string()); self.decorate(&mut err, decorate); - ErrorHandled::Reported(err.emit()) + ErrorHandled::Reported(err.emit().into()) } } } diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs index 088a824fd8f..fa8253d5e49 100644 --- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs @@ -2,7 +2,7 @@ use rustc_attr as attr; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 814b67b46ec..58b5755af07 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -382,7 +382,7 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, rustc_span::DUMMY_SP, "This is likely a const item that is missing from its impl", ); - throw_inval!(AlreadyReported(guar)); + throw_inval!(AlreadyReported(guar.into())); } else { // `find_mir_or_eval_fn` checks that this is a const fn before even calling us, // so this should be unreachable. diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index b2197a0aabb..040eba10eb4 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -7,14 +7,13 @@ use either::{Either, Left, Right}; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::IndexVec; use rustc_middle::mir; -use rustc_middle::mir::interpret::{ErrorHandled, InterpError}; +use rustc_middle::mir::interpret::{ErrorHandled, InterpError, ReportedErrorInfo}; +use rustc_middle::query::TyCtxtAt; use rustc_middle::ty::layout::{ self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers, TyAndLayout, }; -use rustc_middle::ty::{ - self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable, -}; +use rustc_middle::ty::{self, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable}; use rustc_mir_dataflow::storage::always_storage_live_locals; use rustc_session::Limit; use rustc_span::Span; @@ -470,7 +469,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // do not continue if typeck errors occurred (can only occur in local crate) if let Some(err) = body.tainted_by_errors { - throw_inval!(AlreadyReported(err)); + throw_inval!(AlreadyReported(ReportedErrorInfo::tainted_by_errors(err))); } Ok(body) } @@ -517,7 +516,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(None) => throw_inval!(TooGeneric), // FIXME(eddyb) this could be a bit more specific than `AlreadyReported`. - Err(error_reported) => throw_inval!(AlreadyReported(error_reported)), + Err(error_reported) => throw_inval!(AlreadyReported(error_reported.into())), } } @@ -905,7 +904,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| { match err { ErrorHandled::Reported(err) => { - if let Some(span) = span { + if !err.is_tainted_by_errors() && let Some(span) = span { // To make it easier to figure out where this error comes from, also add a note at the current location. self.tcx.sess.span_note_without_error(span, "erroneous constant used"); } diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs index a7f66071fe2..e30af165501 100644 --- a/compiler/rustc_const_eval/src/interpret/operand.rs +++ b/compiler/rustc_const_eval/src/interpret/operand.rs @@ -595,7 +595,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // FIXME(generic_const_exprs): `ConstKind::Expr` should be able to be evaluated ty::ConstKind::Expr(_) => throw_inval!(TooGeneric), ty::ConstKind::Error(reported) => { - throw_inval!(AlreadyReported(reported)) + throw_inval!(AlreadyReported(reported.into())) } ty::ConstKind::Unevaluated(uv) => { let instance = self.resolve(uv.def, uv.substs)?; diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 1b66eca97a5..c36282d5ed4 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -35,8 +35,8 @@ pub mod util; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; +use rustc_middle::query::Providers; use rustc_middle::ty; -use rustc_middle::ty::query::Providers; fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index f46c2d00fe4..3c350e25ba6 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -164,7 +164,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { if let Some(root) = post_contract_node.get(&bb) { break *root; } - let parent = doms.immediate_dominator(bb); + let parent = doms.immediate_dominator(bb).unwrap(); dom_path.push(bb); if !self.body.basic_blocks[parent].is_cleanup { break bb; @@ -448,7 +448,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { }; match debuginfo.value { VarDebugInfoContents::Const(_) => {} - VarDebugInfoContents::Place(place) => check_place(place), + VarDebugInfoContents::Place(place) => { + check_place(place); + if debuginfo.references != 0 && place.projection.last() == Some(&PlaceElem::Deref) { + self.fail( + START_BLOCK.start_location(), + format!("debuginfo {:?}, has both ref and deref", debuginfo), + ); + } + } VarDebugInfoContents::Composite { ty, ref fragments } => { for f in fragments { check_place(f.contents); diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml index c815bb2d197..78f73d193e3 100644 --- a/compiler/rustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -16,6 +16,7 @@ libc = "0.2" measureme = "10.0.0" rustc-rayon-core = { version = "0.5.0", optional = true } rustc-rayon = { version = "0.5.0", optional = true } +rustc_arena = { path = "../rustc_arena" } rustc_graphviz = { path = "../rustc_graphviz" } rustc-hash = "1.1.0" rustc_index = { path = "../rustc_index", package = "rustc_index" } diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs index e76bdac2864..594ed1ad2e7 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs @@ -109,28 +109,27 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> { // they have been placed in the bucket. // // We compute a partial set of immediate dominators here. - let z = parent[w]; - for &v in bucket[z].iter() { + for &v in bucket[w].iter() { // This uses the result of Lemma 5 from section 2 from the original // 1979 paper, to compute either the immediate or relative dominator // for a given vertex v. // // eval returns a vertex y, for which semi[y] is minimum among - // vertices semi[v] +> y *> v. Note that semi[v] = z as we're in the - // z bucket. + // vertices semi[v] +> y *> v. Note that semi[v] = w as we're in the + // w bucket. // // Given such a vertex y, semi[y] <= semi[v] and idom[y] = idom[v]. // If semi[y] = semi[v], though, idom[v] = semi[v]. // // Using this, we can either set idom[v] to be: - // * semi[v] (i.e. z), if semi[y] is z + // * semi[v] (i.e. w), if semi[y] is w // * idom[y], otherwise // // We don't directly set to idom[y] though as it's not necessarily // known yet. The second preorder traversal will cleanup by updating // the idom for any that were missed in this pass. let y = eval(&mut parent, lastlinked, &semi, &mut label, v); - idom[v] = if semi[y] < z { y } else { z }; + idom[v] = if semi[y] < w { y } else { w }; } // This loop computes the semi[w] for w. @@ -213,10 +212,11 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> { // If we don't yet know the idom directly, then push this vertex into // our semidominator's bucket, where it will get processed at a later // stage to compute its immediate dominator. - if parent[w] != semi[w] { + let z = parent[w]; + if z != semi[w] { bucket[semi[w]].push(w); } else { - idom[w] = parent[w]; + idom[w] = z; } // Optimization: We share the parent array between processed and not @@ -242,7 +242,9 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> { immediate_dominators[*node] = Some(pre_order_to_real[idom[idx]]); } - Dominators { post_order_rank, immediate_dominators } + let start_node = graph.start_node(); + immediate_dominators[start_node] = None; + Dominators { start_node, post_order_rank, immediate_dominators } } /// Evaluate the link-eval virtual forest, providing the currently minimum semi @@ -308,6 +310,7 @@ fn compress( /// Tracks the list of dominators for each node. #[derive(Clone, Debug)] pub struct Dominators<N: Idx> { + start_node: N, post_order_rank: IndexVec<N, usize>, // Even though we track only the immediate dominator of each node, it's // possible to get its full list of dominators by looking up the dominator @@ -316,14 +319,14 @@ pub struct Dominators<N: Idx> { } impl<Node: Idx> Dominators<Node> { - /// Whether the given Node has an immediate dominator. + /// Returns true if node is reachable from the start node. pub fn is_reachable(&self, node: Node) -> bool { - self.immediate_dominators[node].is_some() + node == self.start_node || self.immediate_dominators[node].is_some() } - pub fn immediate_dominator(&self, node: Node) -> Node { - assert!(self.is_reachable(node), "node {node:?} is not reachable"); - self.immediate_dominators[node].unwrap() + /// Returns the immediate dominator of node, if any. + pub fn immediate_dominator(&self, node: Node) -> Option<Node> { + self.immediate_dominators[node] } /// Provides an iterator over each dominator up the CFG, for the given Node. @@ -357,12 +360,7 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> { fn next(&mut self) -> Option<Self::Item> { if let Some(node) = self.node { - let dom = self.dominators.immediate_dominator(node); - if dom == node { - self.node = None; // reached the root - } else { - self.node = Some(dom); - } + self.node = self.dominators.immediate_dominator(node); Some(node) } else { None diff --git a/compiler/rustc_data_structures/src/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs index ff31d8f7fdc..5472bb8087e 100644 --- a/compiler/rustc_data_structures/src/graph/dominators/tests.rs +++ b/compiler/rustc_data_structures/src/graph/dominators/tests.rs @@ -8,7 +8,7 @@ fn diamond() { let dominators = dominators(&graph); let immediate_dominators = &dominators.immediate_dominators; - assert_eq!(immediate_dominators[0], Some(0)); + assert_eq!(immediate_dominators[0], None); assert_eq!(immediate_dominators[1], Some(0)); assert_eq!(immediate_dominators[2], Some(0)); assert_eq!(immediate_dominators[3], Some(0)); @@ -30,7 +30,7 @@ fn paper() { assert_eq!(immediate_dominators[3], Some(6)); assert_eq!(immediate_dominators[4], Some(6)); assert_eq!(immediate_dominators[5], Some(6)); - assert_eq!(immediate_dominators[6], Some(6)); + assert_eq!(immediate_dominators[6], None); } #[test] @@ -43,3 +43,40 @@ fn paper_slt() { dominators(&graph); } + +#[test] +fn immediate_dominator() { + let graph = TestGraph::new(1, &[(1, 2), (2, 3)]); + let dominators = dominators(&graph); + assert_eq!(dominators.immediate_dominator(0), None); + assert_eq!(dominators.immediate_dominator(1), None); + assert_eq!(dominators.immediate_dominator(2), Some(1)); + assert_eq!(dominators.immediate_dominator(3), Some(2)); +} + +#[test] +fn transitive_dominator() { + let graph = TestGraph::new( + 0, + &[ + // First tree branch. + (0, 1), + (1, 2), + (2, 3), + (3, 4), + // Second tree branch. + (1, 5), + (5, 6), + // Third tree branch. + (0, 7), + // These links make 0 the dominator for 2 and 3. + (7, 2), + (5, 3), + ], + ); + + let dom_tree = dominators(&graph); + let immediate_dominators = &dom_tree.immediate_dominators; + assert_eq!(immediate_dominators[2], Some(0)); + assert_eq!(immediate_dominators[3], Some(0)); // This used to return Some(1). +} diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 004017ec5f3..5b9b0e106d2 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -26,6 +26,7 @@ #![feature(test)] #![feature(thread_id_value)] #![feature(vec_into_raw_parts)] +#![feature(allocator_api)] #![feature(get_mut_unchecked)] #![feature(lint_reasons)] #![feature(unwrap_infallible)] @@ -77,6 +78,7 @@ pub mod sorted_map; pub mod stable_hasher; mod atomic_ref; pub mod fingerprint; +pub mod marker; pub mod profiling; pub mod sharded; pub mod stack; diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs new file mode 100644 index 00000000000..f8c06f9a814 --- /dev/null +++ b/compiler/rustc_data_structures/src/marker.rs @@ -0,0 +1,257 @@ +cfg_if!( + if #[cfg(not(parallel_compiler))] { + pub auto trait DynSend {} + pub auto trait DynSync {} + + impl<T> DynSend for T {} + impl<T> DynSync for T {} + } else { + #[rustc_on_unimplemented( + message = "`{Self}` doesn't implement `DynSend`. \ + Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`" + )] + // This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()` + // is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a + // `Send` type in `IntoDynSyncSend` will create a `DynSend` type. + pub unsafe auto trait DynSend {} + + #[rustc_on_unimplemented( + message = "`{Self}` doesn't implement `DynSync`. \ + Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`" + )] + // This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()` + // is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a + // `Sync` type in `IntoDynSyncSend` will create a `DynSync` type. + pub unsafe auto trait DynSync {} + + // Same with `Sync` and `Send`. + unsafe impl<T: DynSync + ?Sized> DynSend for &T {} + + macro_rules! impls_dyn_send_neg { + ($([$t1: ty $(where $($generics1: tt)*)?])*) => { + $(impl$(<$($generics1)*>)? !DynSend for $t1 {})* + }; + } + + // Consistent with `std` + impls_dyn_send_neg!( + [std::env::Args] + [std::env::ArgsOs] + [*const T where T: ?Sized] + [*mut T where T: ?Sized] + [std::ptr::NonNull<T> where T: ?Sized] + [std::rc::Rc<T> where T: ?Sized] + [std::rc::Weak<T> where T: ?Sized] + [std::sync::MutexGuard<'_, T> where T: ?Sized] + [std::sync::RwLockReadGuard<'_, T> where T: ?Sized] + [std::sync::RwLockWriteGuard<'_, T> where T: ?Sized] + [std::io::StdoutLock<'_>] + [std::io::StderrLock<'_>] + ); + cfg_if!( + // Consistent with `std` + // `os_imp::Env` is `!Send` in these platforms + if #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] { + impl !DynSend for std::env::VarsOs {} + } + ); + + macro_rules! already_send { + ($([$ty: ty])*) => { + $(unsafe impl DynSend for $ty where $ty: Send {})* + }; + } + + // These structures are already `Send`. + already_send!( + [std::backtrace::Backtrace] + [std::io::Stdout] + [std::io::Stderr] + [std::io::Error] + [std::fs::File] + [rustc_arena::DroplessArena] + [crate::memmap::Mmap] + [crate::profiling::SelfProfiler] + [crate::owned_slice::OwnedSlice] + ); + + macro_rules! impl_dyn_send { + ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => { + $(unsafe impl<$($generics2)*> DynSend for $ty {})* + }; + } + + impl_dyn_send!( + [std::sync::atomic::AtomicPtr<T> where T] + [std::sync::Mutex<T> where T: ?Sized+ DynSend] + [std::sync::mpsc::Sender<T> where T: DynSend] + [std::sync::Arc<T> where T: ?Sized + DynSync + DynSend] + [std::sync::LazyLock<T, F> where T: DynSend, F: DynSend] + [std::collections::HashSet<K, S> where K: DynSend, S: DynSend] + [std::collections::HashMap<K, V, S> where K: DynSend, V: DynSend, S: DynSend] + [std::collections::BTreeMap<K, V, A> where K: DynSend, V: DynSend, A: std::alloc::Allocator + Clone + DynSend] + [Vec<T, A> where T: DynSend, A: std::alloc::Allocator + DynSend] + [Box<T, A> where T: ?Sized + DynSend, A: std::alloc::Allocator + DynSend] + [crate::sync::Lock<T> where T: DynSend] + [crate::sync::RwLock<T> where T: DynSend] + [crate::tagged_ptr::CopyTaggedPtr<P, T, CP> where P: Send + crate::tagged_ptr::Pointer, T: Send + crate::tagged_ptr::Tag, const CP: bool] + [rustc_arena::TypedArena<T> where T: DynSend] + [indexmap::IndexSet<V, S> where V: DynSend, S: DynSend] + [indexmap::IndexMap<K, V, S> where K: DynSend, V: DynSend, S: DynSend] + [thin_vec::ThinVec<T> where T: DynSend] + [smallvec::SmallVec<A> where A: smallvec::Array + DynSend] + ); + + macro_rules! impls_dyn_sync_neg { + ($([$t1: ty $(where $($generics1: tt)*)?])*) => { + $(impl$(<$($generics1)*>)? !DynSync for $t1 {})* + }; + } + + // Consistent with `std` + impls_dyn_sync_neg!( + [std::env::Args] + [std::env::ArgsOs] + [*const T where T: ?Sized] + [*mut T where T: ?Sized] + [std::cell::Cell<T> where T: ?Sized] + [std::cell::RefCell<T> where T: ?Sized] + [std::cell::UnsafeCell<T> where T: ?Sized] + [std::ptr::NonNull<T> where T: ?Sized] + [std::rc::Rc<T> where T: ?Sized] + [std::rc::Weak<T> where T: ?Sized] + [std::cell::OnceCell<T> where T] + [std::sync::mpsc::Receiver<T> where T] + [std::sync::mpsc::Sender<T> where T] + ); + cfg_if!( + // Consistent with `std` + // `os_imp::Env` is `!Sync` in these platforms + if #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] { + impl !DynSync for std::env::VarsOs {} + } + ); + + macro_rules! already_sync { + ($([$ty: ty])*) => { + $(unsafe impl DynSync for $ty where $ty: Sync {})* + }; + } + + // These structures are already `Sync`. + already_sync!( + [std::sync::atomic::AtomicBool] + [std::sync::atomic::AtomicUsize] + [std::sync::atomic::AtomicU8] + [std::sync::atomic::AtomicU32] + [std::sync::atomic::AtomicU64] + [std::backtrace::Backtrace] + [std::io::Error] + [std::fs::File] + [jobserver_crate::Client] + [crate::memmap::Mmap] + [crate::profiling::SelfProfiler] + [crate::owned_slice::OwnedSlice] + ); + + macro_rules! impl_dyn_sync { + ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => { + $(unsafe impl<$($generics2)*> DynSync for $ty {})* + }; + } + + impl_dyn_sync!( + [std::sync::atomic::AtomicPtr<T> where T] + [std::sync::OnceLock<T> where T: DynSend + DynSync] + [std::sync::Mutex<T> where T: ?Sized + DynSend] + [std::sync::Arc<T> where T: ?Sized + DynSync + DynSend] + [std::sync::LazyLock<T, F> where T: DynSend + DynSync, F: DynSend] + [std::collections::HashSet<K, S> where K: DynSync, S: DynSync] + [std::collections::HashMap<K, V, S> where K: DynSync, V: DynSync, S: DynSync] + [std::collections::BTreeMap<K, V, A> where K: DynSync, V: DynSync, A: std::alloc::Allocator + Clone + DynSync] + [Vec<T, A> where T: DynSync, A: std::alloc::Allocator + DynSync] + [Box<T, A> where T: ?Sized + DynSync, A: std::alloc::Allocator + DynSync] + [crate::sync::Lock<T> where T: DynSend] + [crate::sync::RwLock<T> where T: DynSend + DynSync] + [crate::sync::OneThread<T> where T] + [crate::sync::WorkerLocal<T> where T: DynSend] + [crate::intern::Interned<'a, T> where 'a, T: DynSync] + [crate::tagged_ptr::CopyTaggedPtr<P, T, CP> where P: Sync + crate::tagged_ptr::Pointer, T: Sync + crate::tagged_ptr::Tag, const CP: bool] + [parking_lot::lock_api::Mutex<R, T> where R: DynSync, T: ?Sized + DynSend] + [parking_lot::lock_api::RwLock<R, T> where R: DynSync, T: ?Sized + DynSend + DynSync] + [indexmap::IndexSet<V, S> where V: DynSync, S: DynSync] + [indexmap::IndexMap<K, V, S> where K: DynSync, V: DynSync, S: DynSync] + [smallvec::SmallVec<A> where A: smallvec::Array + DynSync] + [thin_vec::ThinVec<T> where T: DynSync] + ); + } +); + +pub fn assert_dyn_sync<T: ?Sized + DynSync>() {} +pub fn assert_dyn_send<T: ?Sized + DynSend>() {} +pub fn assert_dyn_send_val<T: ?Sized + DynSend>(_t: &T) {} +pub fn assert_dyn_send_sync_val<T: ?Sized + DynSync + DynSend>(_t: &T) {} + +#[derive(Copy, Clone)] +pub struct FromDyn<T>(T); + +impl<T> FromDyn<T> { + #[inline(always)] + pub fn from(val: T) -> Self { + // Check that `sync::is_dyn_thread_safe()` is true on creation so we can + // implement `Send` and `Sync` for this structure when `T` + // implements `DynSend` and `DynSync` respectively. + #[cfg(parallel_compiler)] + assert!(crate::sync::is_dyn_thread_safe()); + FromDyn(val) + } + + #[inline(always)] + pub fn into_inner(self) -> T { + self.0 + } +} + +// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true. +#[cfg(parallel_compiler)] +unsafe impl<T: DynSend> Send for FromDyn<T> {} + +// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true. +#[cfg(parallel_compiler)] +unsafe impl<T: DynSync> Sync for FromDyn<T> {} + +impl<T> std::ops::Deref for FromDyn<T> { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +// A wrapper to convert a struct that is already a `Send` or `Sync` into +// an instance of `DynSend` and `DynSync`, since the compiler cannot infer +// it automatically in some cases. (e.g. Box<dyn Send / Sync>) +#[derive(Copy, Clone)] +pub struct IntoDynSyncSend<T: ?Sized>(pub T); + +#[cfg(parallel_compiler)] +unsafe impl<T: ?Sized + Send> DynSend for IntoDynSyncSend<T> {} +#[cfg(parallel_compiler)] +unsafe impl<T: ?Sized + Sync> DynSync for IntoDynSyncSend<T> {} + +impl<T> std::ops::Deref for IntoDynSyncSend<T> { + type Target = T; + + #[inline(always)] + fn deref(&self) -> &T { + &self.0 + } +} + +impl<T> std::ops::DerefMut for IntoDynSyncSend<T> { + #[inline(always)] + fn deref_mut(&mut self) -> &mut T { + &mut self.0 + } +} diff --git a/compiler/rustc_data_structures/src/owned_slice.rs b/compiler/rustc_data_structures/src/owned_slice.rs index 311a42aa42a..cbb3047d884 100644 --- a/compiler/rustc_data_structures/src/owned_slice.rs +++ b/compiler/rustc_data_structures/src/owned_slice.rs @@ -1,5 +1,6 @@ use std::{borrow::Borrow, ops::Deref}; +use crate::sync::Lrc; // Use our fake Send/Sync traits when on not parallel compiler, // so that `OwnedSlice` only implements/requires Send/Sync // for parallel compiler builds. @@ -7,7 +8,7 @@ use crate::sync::{Send, Sync}; /// An owned slice. /// -/// This is similar to `Box<[u8]>` but allows slicing and using anything as the +/// This is similar to `Lrc<[u8]>` but allows slicing and using anything as the /// backing buffer. /// /// See [`slice_owned`] for `OwnedSlice` construction and examples. @@ -16,6 +17,7 @@ use crate::sync::{Send, Sync}; /// /// This is essentially a replacement for `owning_ref` which is a lot simpler /// and even sound! 🌸 +#[derive(Clone)] pub struct OwnedSlice { /// This is conceptually a `&'self.owner [u8]`. bytes: *const [u8], @@ -31,7 +33,7 @@ pub struct OwnedSlice { // \/ // ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770) #[expect(dead_code)] - owner: Box<dyn Send + Sync>, + owner: Lrc<dyn Send + Sync>, } /// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function. @@ -72,10 +74,10 @@ where O: Send + Sync + 'static, F: FnOnce(&O) -> Result<&[u8], E>, { - // We box the owner of the bytes, so it doesn't move. + // We wrap the owner of the bytes in, so it doesn't move. // // Since the owner does not move and we don't access it in any way - // before drop, there is nothing that can invalidate the bytes pointer. + // before dropping, there is nothing that can invalidate the bytes pointer. // // Thus, "extending" the lifetime of the reference returned from `F` is fine. // We pretend that we pass it a reference that lives as long as the returned slice. @@ -83,12 +85,39 @@ where // N.B. the HRTB on the `slicer` is important — without it the caller could provide // a short lived slice, unrelated to the owner. - let owner = Box::new(owner); + let owner = Lrc::new(owner); let bytes = slicer(&*owner)?; Ok(OwnedSlice { bytes, owner }) } +impl OwnedSlice { + /// Slice this slice by `slicer`. + /// + /// # Examples + /// + /// ```rust + /// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned}; + /// let vec = vec![1, 2, 3, 4]; + /// + /// // Identical to slicing via `&v[1..3]` but produces an owned slice + /// let slice: OwnedSlice = slice_owned(vec, |v| &v[..]); + /// assert_eq!(&*slice, [1, 2, 3, 4]); + /// + /// let slice = slice.slice(|slice| &slice[1..][..2]); + /// assert_eq!(&*slice, [2, 3]); + /// ``` + /// + pub fn slice(self, slicer: impl FnOnce(&[u8]) -> &[u8]) -> OwnedSlice { + // This is basically identical to `try_slice_owned`, + // `slicer` can only return slices of its argument or some static data, + // both of which are valid while `owner` is alive. + + let bytes = slicer(&self); + OwnedSlice { bytes, ..self } + } +} + impl Deref for OwnedSlice { type Target = [u8]; @@ -108,11 +137,11 @@ impl Borrow<[u8]> for OwnedSlice { } } -// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Send` +// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send` #[cfg(parallel_compiler)] unsafe impl Send for OwnedSlice {} -// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Sync` +// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync` #[cfg(parallel_compiler)] unsafe impl Sync for OwnedSlice {} diff --git a/compiler/rustc_data_structures/src/owned_slice/tests.rs b/compiler/rustc_data_structures/src/owned_slice/tests.rs index e715fb55362..1eb5378cd1a 100644 --- a/compiler/rustc_data_structures/src/owned_slice/tests.rs +++ b/compiler/rustc_data_structures/src/owned_slice/tests.rs @@ -26,7 +26,7 @@ fn static_storage() { } #[test] -fn slice_the_slice() { +fn slice_owned_the_slice() { let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice); let slice = slice_owned(slice, |s| &s[1..][..4]); let slice = slice_owned(slice, |s| s); @@ -36,6 +36,16 @@ fn slice_the_slice() { } #[test] +fn slice_the_slice() { + let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice) + .slice(|s| &s[1..][..4]) + .slice(|s| s) + .slice(|s| &s[1..]); + + assert_eq!(&*slice, &[1, 2, 3, 4, 5, 6][1..][..4][1..]); +} + +#[test] fn try_and_fail() { let res = try_slice_owned(vec![0], |v| v.get(12..).ok_or(())); @@ -69,6 +79,6 @@ fn drop_drops() { #[test] fn send_sync() { - crate::sync::assert_send::<OwnedSlice>(); - crate::sync::assert_sync::<OwnedSlice>(); + crate::sync::assert_dyn_send::<OwnedSlice>(); + crate::sync::assert_dyn_sync::<OwnedSlice>(); } diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index e73ca56efa0..6c3197d8ec2 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -39,7 +39,7 @@ //! //! [^2] `MTLockRef` is a typedef. -use crate::owned_slice::OwnedSlice; +pub use crate::marker::*; use std::collections::HashMap; use std::hash::{BuildHasher, Hash}; use std::ops::{Deref, DerefMut}; @@ -55,6 +55,43 @@ pub use vec::{AppendOnlyIndexVec, AppendOnlyVec}; mod vec; +mod mode { + use super::Ordering; + use std::sync::atomic::AtomicU8; + + const UNINITIALIZED: u8 = 0; + const DYN_NOT_THREAD_SAFE: u8 = 1; + const DYN_THREAD_SAFE: u8 = 2; + + static DYN_THREAD_SAFE_MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED); + + // Whether thread safety is enabled (due to running under multiple threads). + #[inline] + pub fn is_dyn_thread_safe() -> bool { + match DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) { + DYN_NOT_THREAD_SAFE => false, + DYN_THREAD_SAFE => true, + _ => panic!("uninitialized dyn_thread_safe mode!"), + } + } + + // Only set by the `-Z threads` compile option + pub fn set_dyn_thread_safe_mode(mode: bool) { + let set: u8 = if mode { DYN_THREAD_SAFE } else { DYN_NOT_THREAD_SAFE }; + let previous = DYN_THREAD_SAFE_MODE.compare_exchange( + UNINITIALIZED, + set, + Ordering::Relaxed, + Ordering::Relaxed, + ); + + // Check that the mode was either uninitialized or was already set to the requested mode. + assert!(previous.is_ok() || previous == Err(set)); + } +} + +pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode}; + cfg_if! { if #[cfg(not(parallel_compiler))] { pub unsafe auto trait Send {} @@ -149,7 +186,7 @@ cfg_if! { #[macro_export] macro_rules! parallel { - ($($blocks:tt),*) => { + ($($blocks:block),*) => { // We catch panics here ensuring that all the blocks execute. // This makes behavior consistent with the parallel compiler. let mut panic = None; @@ -168,12 +205,6 @@ cfg_if! { } } - pub use Iterator as ParallelIterator; - - pub fn par_iter<T: IntoIterator>(t: T) -> T::IntoIter { - t.into_iter() - } - pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item) + Sync + Send) { // We catch panics here ensuring that all the loop iterations execute. // This makes behavior consistent with the parallel compiler. @@ -190,7 +221,28 @@ cfg_if! { } } - pub type MetadataRef = OwnedSlice; + pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>( + t: T, + mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R, + ) -> C { + // We catch panics here ensuring that all the loop iterations execute. + let mut panic = None; + let r = t.into_iter().filter_map(|i| { + match catch_unwind(AssertUnwindSafe(|| map(i))) { + Ok(r) => Some(r), + Err(p) => { + if panic.is_none() { + panic = Some(p); + } + None + } + } + }).collect(); + if let Some(panic) = panic { + resume_unwind(panic); + } + r + } pub use std::rc::Rc as Lrc; pub use std::rc::Weak as Weak; @@ -302,49 +354,166 @@ cfg_if! { use parking_lot::RwLock as InnerRwLock; use std::thread; - pub use rayon::{join, scope}; + + #[inline] + pub fn join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB) + where + A: FnOnce() -> RA + DynSend, + B: FnOnce() -> RB + DynSend, + { + if mode::is_dyn_thread_safe() { + let oper_a = FromDyn::from(oper_a); + let oper_b = FromDyn::from(oper_b); + let (a, b) = rayon::join(move || FromDyn::from(oper_a.into_inner()()), move || FromDyn::from(oper_b.into_inner()())); + (a.into_inner(), b.into_inner()) + } else { + (oper_a(), oper_b()) + } + } + + // This function only works when `mode::is_dyn_thread_safe()`. + pub fn scope<'scope, OP, R>(op: OP) -> R + where + OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend, + R: DynSend, + { + let op = FromDyn::from(op); + rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner() + } /// Runs a list of blocks in parallel. The first block is executed immediately on /// the current thread. Use that for the longest running block. #[macro_export] macro_rules! parallel { - (impl $fblock:tt [$($c:tt,)*] [$block:tt $(, $rest:tt)*]) => { + (impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => { parallel!(impl $fblock [$block, $($c,)*] [$($rest),*]) }; - (impl $fblock:tt [$($blocks:tt,)*] []) => { + (impl $fblock:block [$($blocks:expr,)*] []) => { ::rustc_data_structures::sync::scope(|s| { + $(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks); + s.spawn(move |_| block.into_inner()());)* + (|| $fblock)(); + }); + }; + ($fblock:block, $($blocks:block),*) => { + if rustc_data_structures::sync::is_dyn_thread_safe() { + // Reverse the order of the later blocks since Rayon executes them in reverse order + // when using a single thread. This ensures the execution order matches that + // of a single threaded rustc. + parallel!(impl $fblock [] [$($blocks),*]); + } else { + // We catch panics here ensuring that all the blocks execute. + // This makes behavior consistent with the parallel compiler. + let mut panic = None; + if let Err(p) = ::std::panic::catch_unwind( + ::std::panic::AssertUnwindSafe(|| $fblock) + ) { + if panic.is_none() { + panic = Some(p); + } + } $( - s.spawn(|_| $blocks); + if let Err(p) = ::std::panic::catch_unwind( + ::std::panic::AssertUnwindSafe(|| $blocks) + ) { + if panic.is_none() { + panic = Some(p); + } + } )* - $fblock; - }) - }; - ($fblock:tt, $($blocks:tt),*) => { - // Reverse the order of the later blocks since Rayon executes them in reverse order - // when using a single thread. This ensures the execution order matches that - // of a single threaded rustc - parallel!(impl $fblock [] [$($blocks),*]); + if let Some(panic) = panic { + ::std::panic::resume_unwind(panic); + } + } }; } - pub use rayon::iter::ParallelIterator; - use rayon::iter::IntoParallelIterator; + use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator}; - pub fn par_iter<T: IntoParallelIterator>(t: T) -> T::Iter { - t.into_par_iter() - } - - pub fn par_for_each_in<T: IntoParallelIterator>( + pub fn par_for_each_in<I, T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>>( t: T, - for_each: impl Fn(T::Item) + Sync + Send, + for_each: impl Fn(I) + DynSync + DynSend ) { - let ps: Vec<_> = t.into_par_iter().map(|i| catch_unwind(AssertUnwindSafe(|| for_each(i)))).collect(); - ps.into_iter().for_each(|p| if let Err(panic) = p { - resume_unwind(panic) - }); + if mode::is_dyn_thread_safe() { + let for_each = FromDyn::from(for_each); + let panic: Lock<Option<_>> = Lock::new(None); + t.into_par_iter().for_each(|i| if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) { + let mut l = panic.lock(); + if l.is_none() { + *l = Some(p) + } + }); + + if let Some(panic) = panic.into_inner() { + resume_unwind(panic); + } + } else { + // We catch panics here ensuring that all the loop iterations execute. + // This makes behavior consistent with the parallel compiler. + let mut panic = None; + t.into_iter().for_each(|i| { + if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) { + if panic.is_none() { + panic = Some(p); + } + } + }); + if let Some(panic) = panic { + resume_unwind(panic); + } + } } - pub type MetadataRef = OwnedSlice; + pub fn par_map< + I, + T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>, + R: std::marker::Send, + C: FromIterator<R> + FromParallelIterator<R> + >( + t: T, + map: impl Fn(I) -> R + DynSync + DynSend + ) -> C { + if mode::is_dyn_thread_safe() { + let panic: Lock<Option<_>> = Lock::new(None); + let map = FromDyn::from(map); + // We catch panics here ensuring that all the loop iterations execute. + let r = t.into_par_iter().filter_map(|i| { + match catch_unwind(AssertUnwindSafe(|| map(i))) { + Ok(r) => Some(r), + Err(p) => { + let mut l = panic.lock(); + if l.is_none() { + *l = Some(p); + } + None + }, + } + }).collect(); + + if let Some(panic) = panic.into_inner() { + resume_unwind(panic); + } + r + } else { + // We catch panics here ensuring that all the loop iterations execute. + let mut panic = None; + let r = t.into_iter().filter_map(|i| { + match catch_unwind(AssertUnwindSafe(|| map(i))) { + Ok(r) => Some(r), + Err(p) => { + if panic.is_none() { + panic = Some(p); + } + None + } + } + }).collect(); + if let Some(panic) = panic { + resume_unwind(panic); + } + r + } + } /// This makes locks panic if they are already held. /// It is only useful when you are running in a single thread @@ -352,11 +521,6 @@ cfg_if! { } } -pub fn assert_sync<T: ?Sized + Sync>() {} -pub fn assert_send<T: ?Sized + Send>() {} -pub fn assert_send_val<T: ?Sized + Send>(_t: &T) {} -pub fn assert_send_sync_val<T: ?Sized + Sync + Send>(_t: &T) {} - #[derive(Default)] #[cfg_attr(parallel_compiler, repr(align(64)))] pub struct CacheAligned<T>(pub T); diff --git a/compiler/rustc_data_structures/src/sync/worker_local.rs b/compiler/rustc_data_structures/src/sync/worker_local.rs index bfb04ba8a73..d61bb55be68 100644 --- a/compiler/rustc_data_structures/src/sync/worker_local.rs +++ b/compiler/rustc_data_structures/src/sync/worker_local.rs @@ -154,13 +154,6 @@ impl<T> WorkerLocal<T> { } } -impl<T> WorkerLocal<Vec<T>> { - /// Joins the elements of all the worker locals into one Vec - pub fn join(self) -> Vec<T> { - self.into_inner().into_iter().flat_map(|v| v).collect() - } -} - impl<T> Deref for WorkerLocal<T> { type Target = T; diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs index 42c97cc6a9d..a713affa099 100644 --- a/compiler/rustc_driver_impl/src/args.rs +++ b/compiler/rustc_driver_impl/src/args.rs @@ -25,7 +25,7 @@ pub fn arg_expand_all(at_args: &[String]) -> Vec<String> { Ok(arg) => args.extend(arg), Err(err) => rustc_session::early_error( rustc_session::config::ErrorOutputType::default(), - &format!("Failed to load argument file: {err}"), + format!("Failed to load argument file: {err}"), ), } } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 9b16f246193..6c204b894a6 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -256,6 +256,9 @@ fn run_compiler( let sopts = config::build_session_options(&matches); + // Set parallel mode before thread pool creation, which will create `Lock`s. + interface::set_thread_safe_mode(&sopts.unstable_opts); + if let Some(ref code) = matches.opt_str("explain") { handle_explain(diagnostics_registry(), code, sopts.error_format); return Ok(()); @@ -319,7 +322,7 @@ fn run_compiler( 1 => panic!("make_input should have provided valid inputs"), _ => early_error( config.opts.error_format, - &format!( + format!( "multiple input filenames provided (first two filenames are `{}` and `{}`)", matches.free[0], matches.free[1], ), @@ -524,7 +527,7 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) { } } Err(InvalidErrorCode) => { - early_error(output, &format!("{code} is not a valid error code")); + early_error(output, format!("{code} is not a valid error code")); } } } @@ -569,7 +572,7 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp let rlink_data = fs::read(file).unwrap_or_else(|err| { sess.emit_fatal(RlinkUnableToRead { err }); }); - let codegen_results = match CodegenResults::deserialize_rlink(rlink_data) { + let codegen_results = match CodegenResults::deserialize_rlink(sess, rlink_data) { Ok(codegen) => codegen, Err(err) => { match err { @@ -583,10 +586,10 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp rlink_version, }) } - CodegenErrors::RustcVersionMismatch { rustc_version, current_version } => { + CodegenErrors::RustcVersionMismatch { rustc_version } => { sess.emit_fatal(RLinkRustcVersionMismatch { rustc_version, - current_version, + current_version: sess.cfg_version, }) } }; @@ -1099,7 +1102,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> { .map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")), _ => None, }; - early_error(ErrorOutputType::default(), &msg.unwrap_or_else(|| e.to_string())); + early_error(ErrorOutputType::default(), msg.unwrap_or_else(|| e.to_string())); }); // For all options we just parsed, we check a few aspects: @@ -1247,7 +1250,8 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) #[cfg(windows)] if let Some(msg) = info.payload().downcast_ref::<String>() { if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") { - early_error_no_abort(ErrorOutputType::default(), &msg); + // the error code is already going to be reported when the panic unwinds up the stack + let _ = early_error_no_abort(ErrorOutputType::default(), msg.as_str()); return; } }; @@ -1339,7 +1343,7 @@ pub fn init_rustc_env_logger() { /// other than `RUSTC_LOG`. pub fn init_env_logger(env: &str) { if let Err(error) = rustc_log::init_env_logger(env) { - early_error(ErrorOutputType::default(), &error.to_string()); + early_error(ErrorOutputType::default(), error.to_string()); } } @@ -1406,7 +1410,7 @@ pub fn main() -> ! { arg.into_string().unwrap_or_else(|arg| { early_error( ErrorOutputType::default(), - &format!("argument {i} is not valid Unicode: {arg:?}"), + format!("argument {i} is not valid Unicode: {arg:?}"), ) }) }) diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 6c3f677ab8e..0accb4ab96f 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -11,7 +11,7 @@ extern crate tracing; use fluent_bundle::FluentResource; use fluent_syntax::parser::ParserError; use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker}; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_fluent_macro::fluent_messages; use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; @@ -37,16 +37,17 @@ pub use unic_langid::{langid, LanguageIdentifier}; fluent_messages! { "../messages.ftl" } -pub type FluentBundle = fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>; +pub type FluentBundle = + IntoDynSyncSend<fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>>; -#[cfg(parallel_compiler)] +#[cfg(not(parallel_compiler))] fn new_bundle(locales: Vec<LanguageIdentifier>) -> FluentBundle { - FluentBundle::new_concurrent(locales) + IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new(locales)) } -#[cfg(not(parallel_compiler))] +#[cfg(parallel_compiler)] fn new_bundle(locales: Vec<LanguageIdentifier>) -> FluentBundle { - FluentBundle::new(locales) + IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new_concurrent(locales)) } #[derive(Debug)] diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs index 68e57de5e08..3e38d6afb0b 100644 --- a/compiler/rustc_errors/src/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -2303,22 +2303,25 @@ impl EmitterWriter { // Colorize addition/replacements with green. for &SubstitutionHighlight { start, end } in highlight_parts { - // Account for tabs when highlighting (#87972). - let tabs: usize = line_to_add - .chars() - .take(start) - .map(|ch| match ch { - '\t' => 3, - _ => 0, - }) - .sum(); - buffer.set_style_range( - *row_num, - max_line_num_len + 3 + start + tabs, - max_line_num_len + 3 + end + tabs, - Style::Addition, - true, - ); + // This is a no-op for empty ranges + if start != end { + // Account for tabs when highlighting (#87972). + let tabs: usize = line_to_add + .chars() + .take(start) + .map(|ch| match ch { + '\t' => 3, + _ => 0, + }) + .sum(); + buffer.set_style_range( + *row_num, + max_line_num_len + 3 + start + tabs, + max_line_num_len + 3 + end + tabs, + Style::Addition, + true, + ); + } } *row_num += 1; } diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index fcbd9a53b48..5a80024f19b 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -32,7 +32,7 @@ use emitter::{is_case_difference, Emitter, EmitterWriter}; use registry::Registry; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::stable_hasher::{Hash128, StableHasher}; -use rustc_data_structures::sync::{self, Lock, Lrc}; +use rustc_data_structures::sync::{self, IntoDynSyncSend, Lock, Lrc}; use rustc_data_structures::AtomicRef; pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle, @@ -330,12 +330,11 @@ impl CodeSuggestion { }); buf.push_str(&part.snippet); let cur_hi = sm.lookup_char_pos(part.span.hi()); - if cur_hi.line == cur_lo.line && !part.snippet.is_empty() { - // Account for the difference between the width of the current code and the - // snippet being suggested, so that the *later* suggestions are correctly - // aligned on the screen. - acc += len - (cur_hi.col.0 - cur_lo.col.0) as isize; - } + // Account for the difference between the width of the current code and the + // snippet being suggested, so that the *later* suggestions are correctly + // aligned on the screen. Note that cur_hi and cur_lo can be on different + // lines, so cur_hi.col can be smaller than cur_lo.col + acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize); prev_hi = cur_hi; prev_line = sf.get_line(prev_hi.line - 1); for line in part.snippet.split('\n').skip(1) { @@ -409,7 +408,7 @@ struct HandlerInner { err_count: usize, warn_count: usize, deduplicated_err_count: usize, - emitter: Box<dyn Emitter + sync::Send>, + emitter: IntoDynSyncSend<Box<dyn Emitter + sync::Send>>, delayed_span_bugs: Vec<DelayedDiagnostic>, delayed_good_path_bugs: Vec<DelayedDiagnostic>, /// This flag indicates that an expected diagnostic was emitted and suppressed. @@ -478,6 +477,7 @@ pub enum StashKey { /// FRU syntax MaybeFruTypo, CallAssocMethod, + TraitMissingMethod, } fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) { @@ -605,7 +605,7 @@ impl Handler { warn_count: 0, deduplicated_err_count: 0, deduplicated_warn_count: 0, - emitter, + emitter: IntoDynSyncSend(emitter), delayed_span_bugs: Vec::new(), delayed_good_path_bugs: Vec::new(), suppressed_expected_diag: false, @@ -1739,7 +1739,7 @@ impl DelayedDiagnostic { } fn decorate(mut self) -> Diagnostic { - self.inner.note(format!("delayed at {}", self.note)); + self.inner.note(format!("delayed at {}\n{}", self.inner.emitted_at, self.note)); self.inner } } diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs index 52103e46097..0e729b71680 100644 --- a/compiler/rustc_errors/src/tests.rs +++ b/compiler/rustc_errors/src/tests.rs @@ -2,7 +2,7 @@ use crate::error::{TranslateError, TranslateErrorKind}; use crate::fluent_bundle::*; use crate::translation::Translate; use crate::FluentBundle; -use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError}; use rustc_error_messages::langid; use rustc_error_messages::DiagnosticMessage; @@ -27,10 +27,14 @@ fn make_dummy(ftl: &'static str) -> Dummy { let langid_en = langid!("en-US"); #[cfg(parallel_compiler)] - let mut bundle = FluentBundle::new_concurrent(vec![langid_en]); + let mut bundle: FluentBundle = + IntoDynSyncSend(crate::fluent_bundle::bundle::FluentBundle::new_concurrent(vec![ + langid_en, + ])); #[cfg(not(parallel_compiler))] - let mut bundle = FluentBundle::new(vec![langid_en]); + let mut bundle: FluentBundle = + IntoDynSyncSend(crate::fluent_bundle::bundle::FluentBundle::new(vec![langid_en])); bundle.add_resource(resource).expect("Failed to add FTL resources to the bundle."); diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index c1cca89df8c..fd721749066 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -15,7 +15,8 @@ use rustc_attr::{self as attr, Deprecation, Stability}; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::{self, Lrc}; use rustc_errors::{ - Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan, PResult, + Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic, + MultiSpan, PResult, }; use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, RegisteredTools}; @@ -653,13 +654,13 @@ pub enum SyntaxExtensionKind { /// A token-based function-like macro. Bang( /// An expander with signature TokenStream -> TokenStream. - Box<dyn BangProcMacro + sync::Sync + sync::Send>, + Box<dyn BangProcMacro + sync::DynSync + sync::DynSend>, ), /// An AST-based function-like macro. LegacyBang( /// An expander with signature TokenStream -> AST. - Box<dyn TTMacroExpander + sync::Sync + sync::Send>, + Box<dyn TTMacroExpander + sync::DynSync + sync::DynSend>, ), /// A token-based attribute macro. @@ -667,7 +668,7 @@ pub enum SyntaxExtensionKind { /// An expander with signature (TokenStream, TokenStream) -> TokenStream. /// The first TokenSteam is the attribute itself, the second is the annotated item. /// The produced TokenSteam replaces the input TokenSteam. - Box<dyn AttrProcMacro + sync::Sync + sync::Send>, + Box<dyn AttrProcMacro + sync::DynSync + sync::DynSend>, ), /// An AST-based attribute macro. @@ -675,7 +676,7 @@ pub enum SyntaxExtensionKind { /// An expander with signature (AST, AST) -> AST. /// The first AST fragment is the attribute itself, the second is the annotated item. /// The produced AST fragment replaces the input AST fragment. - Box<dyn MultiItemModifier + sync::Sync + sync::Send>, + Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>, ), /// A trivial attribute "macro" that does nothing, @@ -692,14 +693,14 @@ pub enum SyntaxExtensionKind { /// is handled identically to `LegacyDerive`. It should be migrated to /// a token-based representation like `Bang` and `Attr`, instead of /// using `MultiItemModifier`. - Box<dyn MultiItemModifier + sync::Sync + sync::Send>, + Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>, ), /// An AST-based derive macro. LegacyDerive( /// An expander with signature AST -> AST. /// The produced AST fragment is appended to the input AST fragment. - Box<dyn MultiItemModifier + sync::Sync + sync::Send>, + Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>, ), } @@ -1110,7 +1111,7 @@ impl<'a> ExtCtxt<'a> { pub fn struct_span_err<S: Into<MultiSpan>>( &self, sp: S, - msg: &str, + msg: impl Into<DiagnosticMessage>, ) -> DiagnosticBuilder<'a, ErrorGuaranteed> { self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg) } @@ -1132,14 +1133,14 @@ impl<'a> ExtCtxt<'a> { /// Compilation will be stopped in the near future (at the end of /// the macro expansion phase). #[rustc_lint_diagnostics] - pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { + pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) { self.sess.parse_sess.span_diagnostic.span_err(sp, msg); } #[rustc_lint_diagnostics] - pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) { + pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) { self.sess.parse_sess.span_diagnostic.span_warn(sp, msg); } - pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! { + pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! { self.sess.parse_sess.span_diagnostic.span_bug(sp, msg); } pub fn trace_macros_diag(&mut self) { diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs index 7c78970345a..5d369a1879a 100644 --- a/compiler/rustc_expand/src/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -722,7 +722,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); } }; - if fragment_kind == AstFragmentKind::Expr && items.is_empty() { + if matches!( + fragment_kind, + AstFragmentKind::Expr | AstFragmentKind::MethodReceiverExpr + ) && items.is_empty() + { self.cx.emit_err(RemoveExprNotSupported { span }); fragment_kind.dummy(span) } else { @@ -1664,7 +1668,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> { &UNUSED_ATTRIBUTES, attr.span, self.cx.current_expansion.lint_node_id, - &format!("unused attribute `{}`", attr_name), + format!("unused attribute `{}`", attr_name), BuiltinLintDiagnostics::UnusedBuiltinAttribute { attr_name, macro_name: pprust::path_to_string(&call.path), diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 35572292271..cb8b4899e48 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -48,7 +48,7 @@ pub(super) fn failed_to_match_macro<'cx>( let span = token.span.substitute_dummy(sp); - let mut err = cx.struct_span_err(span, &parse_failure_msg(&token)); + let mut err = cx.struct_span_err(span, parse_failure_msg(&token)); err.span_label(span, label); if !def_span.is_dummy() && !cx.source_map().is_imported(def_span) { err.span_label(cx.source_map().guess_head_span(def_span), "when calling this macro"); @@ -170,7 +170,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, } Error(err_sp, msg) => { let span = err_sp.substitute_dummy(self.root_span); - self.cx.struct_span_err(span, msg).emit(); + self.cx.struct_span_err(span, msg.as_str()).emit(); self.result = Some(DummyResult::any(span)); } ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)), diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 75b6396f0be..34f998274e9 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -110,7 +110,7 @@ use crate::mbe::{KleeneToken, TokenTree}; use rustc_ast::token::{Delimiter, Token, TokenKind}; use rustc_ast::{NodeId, DUMMY_NODE_ID}; use rustc_data_structures::fx::FxHashMap; -use rustc_errors::MultiSpan; +use rustc_errors::{DiagnosticMessage, MultiSpan}; use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER}; use rustc_session::parse::ParseSess; use rustc_span::symbol::kw; @@ -593,7 +593,7 @@ fn check_ops_is_prefix( return; } } - buffer_lint(sess, span.into(), node_id, &format!("unknown macro variable `{}`", name)); + buffer_lint(sess, span.into(), node_id, format!("unknown macro variable `{}`", name)); } /// Returns whether `binder_ops` is a prefix of `occurrence_ops`. @@ -626,7 +626,7 @@ fn ops_is_prefix( if i >= occurrence_ops.len() { let mut span = MultiSpan::from_span(span); span.push_span_label(binder.span, "expected repetition"); - let message = &format!("variable '{}' is still repeating at this depth", name); + let message = format!("variable '{}' is still repeating at this depth", name); buffer_lint(sess, span, node_id, message); return; } @@ -642,7 +642,12 @@ fn ops_is_prefix( } } -fn buffer_lint(sess: &ParseSess, span: MultiSpan, node_id: NodeId, message: &str) { +fn buffer_lint( + sess: &ParseSess, + span: MultiSpan, + node_id: NodeId, + message: impl Into<DiagnosticMessage>, +) { // Macros loaded from other crates have dummy node ids. if node_id != DUMMY_NODE_ID { sess.buffer_lint(&META_VARIABLE_MISUSE, span, node_id, message); diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs index a07cb65170d..d523d3eacbe 100644 --- a/compiler/rustc_expand/src/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -510,7 +510,7 @@ fn out_of_bounds_err<'a>( must be less than {max}" ) }; - cx.struct_span_err(span, &msg) + cx.struct_span_err(span, msg) } fn transcribe_metavar_expr<'a>( diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index f4615445f8e..57e55752027 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -321,6 +321,8 @@ declare_features! ( (active, c_unwind, "1.52.0", Some(74990), None), /// Allows using C-variadics. (active, c_variadic, "1.34.0", Some(44930), None), + /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour. + (active, cfg_overflow_checks, "CURRENT_RUSTC_VERSION", Some(111466), None), /// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used. (active, cfg_sanitize, "1.41.0", Some(39699), None), /// Allows `cfg(target_abi = "...")`. @@ -336,7 +338,7 @@ declare_features! ( /// Allow conditional compilation depending on rust version (active, cfg_version, "1.45.0", Some(64796), None), /// Allows to use the `#[cfi_encoding = ""]` attribute. - (active, cfi_encoding, "1.69.0", Some(89653), None), + (active, cfi_encoding, "CURRENT_RUSTC_VERSION", Some(89653), None), /// Allows `for<...>` on closures and generators. (active, closure_lifetime_binder, "1.64.0", Some(97362), None), /// Allows `#[track_caller]` on closures and generators. diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index fe05d4590e7..61cfbf5c5e5 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -24,6 +24,7 @@ pub type GatedCfg = (Symbol, Symbol, GateFn); /// `cfg(...)`'s that are feature gated. const GATED_CFGS: &[GatedCfg] = &[ // (name in cfg, feature, function to check if the feature is enabled) + (sym::overflow_checks, sym::cfg_overflow_checks, cfg_fn!(cfg_overflow_checks)), (sym::target_abi, sym::cfg_target_abi, cfg_fn!(cfg_target_abi)), (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), ( diff --git a/compiler/rustc_hir/src/errors.rs b/compiler/rustc_hir/src/errors.rs deleted file mode 100644 index e593ed1044a..00000000000 --- a/compiler/rustc_hir/src/errors.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::LangItem; - -#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)] -pub struct LangItemError(pub LangItem); - -impl ToString for LangItemError { - fn to_string(&self) -> String { - format!("requires `{}` lang_item", self.0.name()) - } -} diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 38cd5865cc3..932f0396282 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2662,7 +2662,10 @@ pub enum OpaqueTyOrigin { /// `async fn` AsyncFn(LocalDefId), /// type aliases: `type Foo = impl Trait;` - TyAlias, + TyAlias { + /// associated types in impl blocks for traits. + in_assoc_ty: bool, + }, } /// The various kinds of types recognized by the compiler. diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 1f08befb180..4b3bc816b95 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -8,7 +8,6 @@ //! * Functions called by the compiler itself. use crate::def_id::DefId; -use crate::errors::LangItemError; use crate::{MethodKind, Target}; use rustc_ast as ast; @@ -42,13 +41,6 @@ impl LanguageItems { self.items[item as usize] = Some(def_id); } - /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`. - /// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`, - /// returns an error encapsulating the `LangItem`. - pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> { - self.get(it).ok_or_else(|| LangItemError(it)) - } - pub fn iter(&self) -> impl Iterator<Item = (LangItem, DefId)> + '_ { self.items .iter() diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs index 98d967cc0b8..616de57dc63 100644 --- a/compiler/rustc_hir/src/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -30,7 +30,6 @@ pub mod def; pub mod def_path_hash_map; pub mod definitions; pub mod diagnostic_items; -pub mod errors; pub use rustc_span::def_id; mod hir; pub mod hir_id; diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs index c7ac01b3334..a40a0178710 100644 --- a/compiler/rustc_hir/src/tests.rs +++ b/compiler/rustc_hir/src/tests.rs @@ -10,13 +10,13 @@ fn def_path_hash_depends_on_crate_id() { // the crate-id of the defining crate. This is a desirable property // because the crate-id can be more easily changed than the DefPath // of an item, so, in the case of a crate-local DefPathHash collision, - // the user can simply "role the dice again" for all DefPathHashes in + // the user can simply "roll the dice again" for all DefPathHashes in // the crate by changing the crate disambiguator (e.g. via bumping the // crate's version number). create_session_if_not_set_then(Edition::Edition2024, |_| { - let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()]); - let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()]); + let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()], ""); + let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()], ""); let h0 = mk_test_hash(id0); let h1 = mk_test_hash(id1); diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs index ed011b9086a..39d1d1f2de5 100644 --- a/compiler/rustc_hir_analysis/src/astconv/generics.rs +++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs @@ -24,7 +24,7 @@ fn generic_arg_mismatch_err( arg: &GenericArg<'_>, param: &GenericParamDef, possible_ordering_error: bool, - help: Option<&str>, + help: Option<String>, ) -> ErrorGuaranteed { let sess = tcx.sess; let mut err = struct_span_err!( @@ -300,7 +300,7 @@ pub fn create_substs_for_generic_args<'tcx, 'a>( arg, param, !args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()), - Some(&format!( + Some(format!( "reorder the arguments: {}: `<{}>`", param_types_present .into_iter() diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 6ac1df6a079..cf082f1ffaa 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -19,7 +19,7 @@ use rustc_ast::TraitObjectSyntax; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_errors::{ struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError, - MultiSpan, + MultiSpan, StashKey, }; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; @@ -38,7 +38,6 @@ use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt} use rustc_middle::ty::{DynKind, ToPredicate}; use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS}; use rustc_span::edit_distance::find_best_match_for_name; -use rustc_span::edition::Edition; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_span::{sym, Span, DUMMY_SP}; use rustc_target::spec::abi; @@ -464,7 +463,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.astconv.ct_infer(ty, Some(param), inf.span).into() } else { self.inferred_params.push(inf.span); - tcx.const_error(ty).into() + tcx.const_error_misc(ty).into() } } _ => unreachable!(), @@ -518,7 +517,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .no_bound_vars() .expect("const parameter types cannot be generic"); if let Err(guar) = ty.error_reported() { - return tcx.const_error_with_guaranteed(ty, guar).into(); + return tcx.const_error(ty, guar).into(); } if !infer_args && has_default { tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into() @@ -527,7 +526,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.astconv.ct_infer(ty, Some(param), self.span).into() } else { // We've already errored above about the mismatch. - tcx.const_error(ty).into() + tcx.const_error_misc(ty).into() } } } @@ -1387,7 +1386,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { term = match def_kind { hir::def::DefKind::AssocTy => tcx.ty_error(reported).into(), hir::def::DefKind::AssocConst => tcx - .const_error_with_guaranteed( + .const_error( tcx.type_of(assoc_item_def_id) .subst(tcx, projection_ty.skip_binder().substs), reported, @@ -3718,7 +3717,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { )); } - if self_ty.span.edition() >= Edition::Edition2021 { + if self_ty.span.edition().rust_2021() { let msg = "trait objects must include the `dyn` keyword"; let label = "add `dyn` keyword before this trait"; let mut diag = @@ -3732,7 +3731,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } // check if the impl trait that we are considering is a impl of a local trait self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag); - diag.emit(); + diag.stash(self_ty.span, StashKey::TraitMissingMethod); } else { let msg = "trait objects without an explicit `dyn` are deprecated"; tcx.struct_span_lint_hir( diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs index 1cf93c86f4f..d6d1498d708 100644 --- a/compiler/rustc_hir_analysis/src/autoderef.rs +++ b/compiler/rustc_hir_analysis/src/autoderef.rs @@ -1,6 +1,5 @@ use crate::errors::AutoDerefReachedRecursionLimit; use crate::traits::query::evaluate_obligation::InferCtxtExt; -use crate::traits::NormalizeExt; use crate::traits::{self, TraitEngine, TraitEngineExt}; use rustc_infer::infer::InferCtxt; use rustc_middle::ty::TypeVisitableExt; @@ -9,6 +8,7 @@ use rustc_session::Limit; use rustc_span::def_id::LocalDefId; use rustc_span::def_id::LOCAL_CRATE; use rustc_span::Span; +use rustc_trait_selection::traits::StructurallyNormalizeExt; #[derive(Copy, Clone, Debug)] pub enum AutoderefKind { @@ -66,14 +66,27 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> { } // Otherwise, deref if type is derefable: - let (kind, new_ty) = - if let Some(mt) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) { - (AutoderefKind::Builtin, mt.ty) - } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { - (AutoderefKind::Overloaded, ty) + let (kind, new_ty) = if let Some(ty::TypeAndMut { ty, .. }) = + self.state.cur_ty.builtin_deref(self.include_raw_pointers) + { + debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty)); + // NOTE: we may still need to normalize the built-in deref in case + // we have some type like `&<Ty as Trait>::Assoc`, since users of + // autoderef expect this type to have been structurally normalized. + if self.infcx.tcx.trait_solver_next() + && let ty::Alias(ty::Projection, _) = ty.kind() + { + let (normalized_ty, obligations) = self.structurally_normalize(ty)?; + self.state.obligations.extend(obligations); + (AutoderefKind::Builtin, normalized_ty) } else { - return None; - }; + (AutoderefKind::Builtin, ty) + } + } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) { + (AutoderefKind::Overloaded, ty) + } else { + return None; + }; if new_ty.references_error() { return None; @@ -119,14 +132,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> { debug!("overloaded_deref_ty({:?})", ty); - let tcx = self.infcx.tcx; // <ty as Deref> let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]); - let cause = traits::ObligationCause::misc(self.span, self.body_id); - let obligation = traits::Obligation::new( tcx, cause.clone(), @@ -138,26 +148,48 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { return None; } - let normalized_ty = self + let (normalized_ty, obligations) = + self.structurally_normalize(tcx.mk_projection(tcx.lang_items().deref_target()?, [ty]))?; + debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); + self.state.obligations.extend(obligations); + + Some(self.infcx.resolve_vars_if_possible(normalized_ty)) + } + + #[instrument(level = "debug", skip(self), ret)] + pub fn structurally_normalize( + &self, + ty: Ty<'tcx>, + ) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> { + let tcx = self.infcx.tcx; + let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx); + + let cause = traits::ObligationCause::misc(self.span, self.body_id); + let normalized_ty = match self .infcx .at(&cause, self.param_env) - .normalize(tcx.mk_projection(tcx.lang_items().deref_target()?, trait_ref.substs)); - let mut fulfillcx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx); - let normalized_ty = - normalized_ty.into_value_registering_obligations(self.infcx, &mut *fulfillcx); - let errors = fulfillcx.select_where_possible(&self.infcx); + .structurally_normalize(ty, &mut *fulfill_cx) + { + Ok(normalized_ty) => normalized_ty, + Err(errors) => { + // This shouldn't happen, except for evaluate/fulfill mismatches, + // but that's not a reason for an ICE (`predicate_may_hold` is conservative + // by design). + debug!(?errors, "encountered errors while fulfilling"); + return None; + } + }; + + let errors = fulfill_cx.select_where_possible(&self.infcx); if !errors.is_empty() { // This shouldn't happen, except for evaluate/fulfill mismatches, // but that's not a reason for an ICE (`predicate_may_hold` is conservative // by design). - debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors); + debug!(?errors, "encountered errors while fulfilling"); return None; } - let obligations = fulfillcx.pending_obligations(); - debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations); - self.state.obligations.extend(obligations); - Some(self.infcx.resolve_vars_if_possible(normalized_ty)) + Some((normalized_ty, fulfill_cx.pending_obligations())) } /// Returns the final type we ended up with, which may be an inference diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 5187e63f8e3..d3495d3dbd7 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -397,7 +397,7 @@ fn check_opaque_meets_bounds<'tcx>( ) { let defining_use_anchor = match *origin { hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did, - hir::OpaqueTyOrigin::TyAlias => def_id, + hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id), }; let param_env = tcx.param_env(defining_use_anchor); @@ -455,10 +455,10 @@ fn check_opaque_meets_bounds<'tcx>( // They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`. // We don't have to check them here because their well-formedness follows from the WF of // the projection input types in the defining- and use-sites. - hir::OpaqueTyOrigin::TyAlias + hir::OpaqueTyOrigin::TyAlias { .. } if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {} // Can have different predicates to their defining use - hir::OpaqueTyOrigin::TyAlias => { + hir::OpaqueTyOrigin::TyAlias { .. } => { let wf_tys = ocx.assumed_wf_types(param_env, span, def_id); let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys); let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds); @@ -1514,8 +1514,8 @@ fn opaque_type_cycle_error( } if tcx.sess.opts.unstable_opts.drop_tracking_mir && let DefKind::Generator = tcx.def_kind(closure_def_id) + && let Some(generator_layout) = tcx.mir_generator_witnesses(closure_def_id) { - let generator_layout = tcx.mir_generator_witnesses(closure_def_id); for interior_ty in &generator_layout.field_tys { label_match(interior_ty.ty, interior_ty.source_info.span); } diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs index 5ba1ca1c807..e0ba255cc06 100644 --- a/compiler/rustc_hir_analysis/src/check/dropck.rs +++ b/compiler/rustc_hir_analysis/src/check/dropck.rs @@ -6,7 +6,7 @@ use rustc_errors::{struct_span_err, ErrorGuaranteed}; use rustc_infer::infer::outlives::env::OutlivesEnvironment; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::util::IgnoreRegions; +use rustc_middle::ty::util::CheckRegions; use rustc_middle::ty::{self, TyCtxt}; use rustc_trait_selection::traits::{self, ObligationCtxt}; @@ -81,7 +81,7 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>( self_type_did: DefId, adt_to_impl_substs: SubstsRef<'tcx>, ) -> Result<(), ErrorGuaranteed> { - let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, IgnoreRegions::No) else { + let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, CheckRegions::OnlyEarlyBound) else { return Ok(()) }; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 08154cdae47..3971a4c01d6 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -78,7 +78,7 @@ use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::Visitor; use rustc_index::bit_set::BitSet; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{InternalSubsts, SubstsRef}; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index 862f0a9b0e2..8918553e5f9 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -12,7 +12,7 @@ use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs}; use rustc_infer::infer::outlives::obligations::TypeOutlives; use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt}; use rustc_middle::mir::ConstraintCategory; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::trait_def::TraitSpecializationKind; use rustc_middle::ty::{ self, AdtKind, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index d05d8508408..a98d8e17153 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -298,9 +298,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span)); - let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| { - tcx.sess.fatal(format!("`CoerceUnsized` implementation {}", err.to_string())); - }); + let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span)); let source = tcx.type_of(impl_did).subst_identity(); let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity(); diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs index cd2ec2bef20..4524b87a418 100644 --- a/compiler/rustc_hir_analysis/src/coherence/mod.rs +++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs @@ -8,7 +8,7 @@ use crate::errors; use rustc_errors::{error_code, struct_span_err}; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::sym; use rustc_trait_selection::traits; diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 272177dfbd0..23beacd2a8c 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -6,7 +6,7 @@ use rustc_errors::{struct_span_err, DelayDm}; use rustc_errors::{Diagnostic, ErrorGuaranteed}; use rustc_hir as hir; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::util::IgnoreRegions; +use rustc_middle::ty::util::CheckRegions; use rustc_middle::ty::{ self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, @@ -507,7 +507,7 @@ fn lint_auto_trait_impl<'tcx>( // Impls which completely cover a given root type are fine as they // disable auto impls entirely. So only lint if the substs // are not a permutation of the identity substs. - let Err(arg) = tcx.uses_unique_generic_params(substs, IgnoreRegions::Yes) else { + let Err(arg) = tcx.uses_unique_generic_params(substs, CheckRegions::No) else { // ok return; }; diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index b65817ee95e..22502bd4fdb 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -28,7 +28,7 @@ use rustc_hir::{GenericParamKind, Node}; use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::ObligationCause; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::util::{Discr, IntTypeExt}; use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -73,7 +73,6 @@ pub fn provide(providers: &mut Providers) { fn_sig, impl_trait_ref, impl_polarity, - is_foreign_item, generator_kind, collect_mod_item_types, is_type_alias_impl_trait, @@ -1466,10 +1465,6 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( fty } -fn is_foreign_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - matches!(tcx.hir().get_by_def_id(def_id), Node::ForeignItem(..)) -} - fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorKind> { match tcx.hir().get_by_def_id(def_id) { Node::Expr(&rustc_hir::Expr { @@ -1483,7 +1478,7 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorK fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool { match tcx.hir().get_by_def_id(def_id) { Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => { - matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias) + matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }) } _ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id), } diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index ab2932bf969..ed60998ec8d 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -159,7 +159,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { } Some(fn_def_id.to_def_id()) } - ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => { + ItemKind::OpaqueTy(hir::OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { .. }, + .. + }) => { let parent_id = tcx.hir().get_parent_item(hir_id); assert_ne!(parent_id, hir::CRATE_OWNER_ID); debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id); diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index e04658c8e77..a33990813b8 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -721,7 +721,7 @@ pub(super) fn type_param_predicates( | ItemKind::TyAlias(_, generics) | ItemKind::OpaqueTy(OpaqueTy { generics, - origin: hir::OpaqueTyOrigin::TyAlias, + origin: hir::OpaqueTyOrigin::TyAlias { .. }, .. }) | ItemKind::Enum(_, generics) diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index 5c7f7f10b17..794812a5ce7 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -17,6 +17,7 @@ use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeNa use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::*; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_session::lint; use rustc_span::def_id::DefId; @@ -232,8 +233,8 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> { type ScopeRef<'a> = &'a Scope<'a>; -pub(crate) fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { resolve_bound_vars, named_variable_map: |tcx, id| tcx.resolve_bound_vars(id).defs.get(&id), @@ -526,7 +527,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { }); } hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias, .. + origin: hir::OpaqueTyOrigin::TyAlias { .. }, + .. }) => { // Opaque types are visited when we visit the // `TyKind::OpaqueDef`, so that they have the lifetimes from @@ -707,7 +709,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let opaque_ty = self.tcx.hir().item(item_id); match &opaque_ty.kind { hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias, + origin: hir::OpaqueTyOrigin::TyAlias { .. }, .. }) => { intravisit::walk_ty(self, ty); diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index 8df0166f76b..ca430a5e863 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -164,7 +164,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else { return tcx.ty_error_with_message( tcx.def_span(def_id), - &format!("unable to find type-dependent def for {:?}", parent_node_id), + format!("unable to find type-dependent def for {:?}", parent_node_id), ); }; let idx = segment @@ -205,14 +205,14 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { } else { return tcx.ty_error_with_message( tcx.def_span(def_id), - &format!("unable to find const parent for {} in pat {:?}", hir_id, pat), + format!("unable to find const parent for {} in pat {:?}", hir_id, pat), ); } } _ => { return tcx.ty_error_with_message( tcx.def_span(def_id), - &format!("unexpected const parent path {:?}", parent_node), + format!("unexpected const parent path {:?}", parent_node), ); } }; @@ -243,7 +243,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { None => { return tcx.ty_error_with_message( tcx.def_span(def_id), - &format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), + format!("unexpected anon const res {:?} in path: {:?}", segment.res, path), ); } }; @@ -253,7 +253,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { _ => return tcx.ty_error_with_message( tcx.def_span(def_id), - &format!("unexpected const parent in type_of(): {parent_node:?}"), + format!("unexpected const parent in type_of(): {parent_node:?}"), ), }; @@ -279,7 +279,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { } else { return tcx.ty_error_with_message( tcx.def_span(def_id), - &format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"), + format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"), ); } } @@ -426,9 +426,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty let substs = InternalSubsts::identity_for_item(tcx, def_id); tcx.mk_adt(def, substs) } - ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => { - find_opaque_ty_constraints_for_tait(tcx, def_id) - } + ItemKind::OpaqueTy(OpaqueTy { + origin: hir::OpaqueTyOrigin::TyAlias { .. }, + .. + }) => find_opaque_ty_constraints_for_tait(tcx, def_id), // Opaque types desugared from `impl Trait`. ItemKind::OpaqueTy(OpaqueTy { origin: diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 8269a6ddea5..e4c6e6e391a 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{ForeignItem, ForeignItemKind}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{ObligationCause, WellFormedLoc}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder}; use rustc_span::def_id::LocalDefId; use rustc_trait_selection::traits::{self, ObligationCtxt}; diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs index f070b4f9bae..612d4ff3df8 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs @@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_errors::struct_span_err; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::{Span, Symbol}; diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 3fe34f23aef..5cd2cd50c11 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -104,7 +104,7 @@ use rustc_hir as hir; use rustc_hir::Node; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::middle; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::util; use rustc_session::{config::EntryFnType, parse::feature_err}; diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index 42612eed750..a8596c707f3 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -1,7 +1,7 @@ use hir::Node; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt}; use rustc_span::symbol::sym; diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs index e735b048d73..3ebd9e134bf 100644 --- a/compiler/rustc_hir_analysis/src/variance/mod.rs +++ b/compiler/rustc_hir_analysis/src/variance/mod.rs @@ -6,7 +6,7 @@ use rustc_arena::DroplessArena; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt}; use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable}; use std::ops::ControlFlow; diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl index aa664031a87..4a669e3f8b8 100644 --- a/compiler/rustc_hir_typeck/messages.ftl +++ b/compiler/rustc_hir_typeck/messages.ftl @@ -79,3 +79,14 @@ hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but hir_typeck_suggest_boxing_note = for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `Box::new` + +hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method -> + [true] {""} + *[other] {" "}in the current scope +} + +hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty -> + [NONE] {""} + [implement] , perhaps you need to implement it + *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it +} diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs index ce30bbeca0b..102a313067f 100644 --- a/compiler/rustc_hir_typeck/src/errors.rs +++ b/compiler/rustc_hir_typeck/src/errors.rs @@ -1,4 +1,6 @@ //! Errors emitted by `rustc_hir_typeck`. +use std::borrow::Cow; + use crate::fluent_generated as fluent; use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, MultiSpan, SubdiagnosticMessage}; use rustc_macros::{Diagnostic, Subdiagnostic}; @@ -295,3 +297,25 @@ pub enum SuggestBoxing { end: Span, }, } + +#[derive(Diagnostic)] +#[diag(hir_typeck_no_associated_item, code = "E0599")] +pub struct NoAssociatedItem { + #[primary_span] + pub span: Span, + pub item_kind: &'static str, + pub item_name: Ident, + pub ty_prefix: Cow<'static, str>, + pub ty_str: String, + pub trait_missing_method: bool, +} + +#[derive(Subdiagnostic)] +#[note(hir_typeck_candidate_trait_note)] +pub struct CandidateTraitNote { + #[primary_span] + pub span: Span, + pub trait_name: String, + pub item_name: Ident, + pub action_or_ty: String, +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index bba049c3819..adc1b090af6 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -721,7 +721,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // ICE this expression in particular (see #43162). if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind { if path.segments.len() == 1 && path.segments[0].ident.name == sym::rust { - fatally_break_rust(self.tcx.sess); + fatally_break_rust(self.tcx); } } } @@ -1245,6 +1245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error, Some((rcvr, args)), expected, + false, ) { err.emit(); } @@ -2468,7 +2469,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { self.suggest_method_call( &mut err, - &format!("a method `{field}` also exists, call it with parentheses"), + format!("a method `{field}` also exists, call it with parentheses"), field, expr_t, expr, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 9e78e6acba5..9721e3b427d 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -4,7 +4,7 @@ use crate::rvalue_scopes; use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy}; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan}; +use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; @@ -35,7 +35,9 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::Span; use rustc_target::abi::FieldIdx; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _; -use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCauseCode, ObligationCtxt}; +use rustc_trait_selection::traits::{ + self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt, +}; use std::collections::hash_map::Entry; use std::slice; @@ -853,6 +855,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let item_name = item_segment.ident; let result = self .resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id) + .and_then(|r| { + // lint bare trait if the method is found in the trait + if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { + diag.emit(); + } + Ok(r) + }) .or_else(|error| { let guar = self .tcx @@ -863,17 +872,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => Err(guar), }; + let trait_missing_method = + matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait(); // If we have a path like `MyTrait::missing_method`, then don't register // a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise, // register a WF obligation so that we can detect any additional // errors in the self type. - if !(matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait()) { + if !trait_missing_method { self.register_wf_obligation( ty.raw.into(), qself.span, traits::WellFormed(None), ); } + + // emit or cancel the diagnostic for bare traits + if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) { + if trait_missing_method { + // cancel the diag for bare traits when meeting `MyTrait::missing_method` + diag.cancel(); + } else { + diag.emit(); + } + } + if item_name.name != kw::Empty { if let Some(mut e) = self.report_method_error( span, @@ -883,10 +905,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error, None, Expectation::NoExpectation, + trait_missing_method && span.edition().rust_2021(), // emits missing method for trait only after edition 2021 ) { e.emit(); } } + result }); @@ -1438,10 +1462,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Resolves `typ` by a single level if `typ` is a type variable. + /// + /// When the new solver is enabled, this will also attempt to normalize + /// the type if it's a projection (note that it will not deeply normalize + /// projections within the type, just the outermost layer of the type). + /// /// If no resolution is possible, then an error is reported. /// Numeric inference variables may be left unresolved. pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - let ty = self.resolve_vars_with_obligations(ty); + let mut ty = self.resolve_vars_with_obligations(ty); + + if self.tcx.trait_solver_next() + && let ty::Alias(ty::Projection, _) = ty.kind() + { + match self + .at(&self.misc(sp), self.param_env) + .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut()) + { + Ok(normalized_ty) => { + ty = normalized_ty; + }, + Err(errors) => { + let guar = self.err_ctxt().report_fulfillment_errors(&errors); + return self.tcx.ty_error(guar); + } + } + } + if !ty.is_ty_var() { ty } else { diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index dcc323493f4..64426c4cbbb 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -68,11 +68,10 @@ use rustc_hir::{HirIdMap, Node}; use rustc_hir_analysis::astconv::AstConv; use rustc_hir_analysis::check::check_abi; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_middle::query::Providers; use rustc_middle::traits; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_session::config; -use rustc_session::Session; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{sym, Span}; @@ -438,8 +437,8 @@ enum TupleArgumentsFlag { TupleArguments, } -fn fatally_break_rust(sess: &Session) { - let handler = sess.diagnostic(); +fn fatally_break_rust(tcx: TyCtxt<'_>) { + let handler = tcx.sess.diagnostic(); handler.span_bug_no_panic( MultiSpan::new(), "It looks like you're trying to break rust; would you like some ICE?", @@ -451,7 +450,7 @@ fn fatally_break_rust(sess: &Session) { ); handler.note_without_error(format!( "rustc {} running on {}", - option_env!("CFG_VERSION").unwrap_or("unknown_version"), + tcx.sess.cfg_version, config::host_triple(), )); } diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs index 9155a3d8daa..59bf45f0ed2 100644 --- a/compiler/rustc_hir_typeck/src/method/confirm.rs +++ b/compiler/rustc_hir_typeck/src/method/confirm.rs @@ -158,7 +158,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let Some((ty, n)) = autoderef.nth(pick.autoderefs) else { return self.tcx.ty_error_with_message( rustc_span::DUMMY_SP, - &format!("failed autoderef {}", pick.autoderefs), + format!("failed autoderef {}", pick.autoderefs), ); }; assert_eq!(n, pick.autoderefs); diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 5963a1632c5..6f4d674ba10 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -13,11 +13,12 @@ pub use self::MethodError::*; use crate::errors::OpMethodGenericParams; use crate::FnCtxt; use rustc_data_structures::sync::Lrc; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, Diagnostic, SubdiagnosticMessage}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace}; use rustc_hir::def_id::DefId; use rustc_infer::infer::{self, InferOk}; +use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt}; @@ -28,7 +29,7 @@ use rustc_trait_selection::traits::{self, NormalizeExt}; use self::probe::{IsSuggestion, ProbeScope}; -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { probe::provide(providers); } @@ -129,7 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub(crate) fn suggest_method_call( &self, err: &mut Diagnostic, - msg: &str, + msg: impl Into<SubdiagnosticMessage> + std::fmt::Debug, method_name: Ident, self_ty: Ty<'tcx>, call_expr: &hir::Expr<'tcx>, diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 483e17460b3..f91f4f887c6 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -16,6 +16,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; use rustc_middle::middle::stability; +use rustc_middle::query::Providers; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::AssocItem; use rustc_middle::ty::GenericParamDefKind; @@ -495,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { providers.method_autoderef_steps = method_autoderef_steps; } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 486c217707e..17364509844 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2,6 +2,8 @@ //! found or is otherwise invalid. use crate::errors; +use crate::errors::CandidateTraitNote; +use crate::errors::NoAssociatedItem; use crate::Expectation; use crate::FnCtxt; use rustc_ast::ast::Mutability; @@ -38,6 +40,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _ use rustc_trait_selection::traits::{ FulfillmentError, Obligation, ObligationCause, ObligationCauseCode, }; +use std::borrow::Cow; use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope}; use super::{CandidateSource, MethodError, NoMatchData}; @@ -112,6 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error: MethodError<'tcx>, args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>, expected: Expectation<'tcx>, + trait_missing_method: bool, ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> { // Avoid suggestions when we don't know what's going on. if rcvr_ty.references_error() { @@ -136,6 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg_span, &mut no_match_data, expected, + trait_missing_method, ); } @@ -278,12 +283,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { sugg_span: Span, no_match_data: &mut NoMatchData<'tcx>, expected: Expectation<'tcx>, + trait_missing_method: bool, ) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> { let mode = no_match_data.mode; let tcx = self.tcx; let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty); - let (ty_str, ty_file) = tcx.short_ty_string(rcvr_ty); - let short_ty_str = with_forced_trimmed_paths!(rcvr_ty.to_string()); + let ((mut ty_str, ty_file), short_ty_str) = if trait_missing_method + && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() { + ((predicates.to_string(), None), with_forced_trimmed_paths!(predicates.to_string())) + } else { + (tcx.short_ty_string(rcvr_ty), with_forced_trimmed_paths!(rcvr_ty.to_string())) + }; let is_method = mode == Mode::MethodCall; let unsatisfied_predicates = &no_match_data.unsatisfied_predicates; let similar_candidate = no_match_data.similar_candidate; @@ -355,25 +365,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { self.suggest_missing_writer(rcvr_ty, args) } else { - struct_span_err!( - tcx.sess, + tcx.sess.create_err(NoAssociatedItem { span, - E0599, - "no {} named `{}` found for {} `{}` in the current scope", item_kind, item_name, - rcvr_ty.prefix_string(self.tcx), - ty_str_reported, - ) + ty_prefix: if trait_missing_method { + // FIXME(mu001999) E0599 maybe not suitable here because it is for types + Cow::from("trait") + } else { + rcvr_ty.prefix_string(self.tcx) + }, + ty_str: ty_str_reported, + trait_missing_method, + }) }; if tcx.sess.source_map().is_multiline(sugg_span) { err.span_label(sugg_span.with_hi(span.lo()), ""); } - let ty_str = if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 { - short_ty_str - } else { - ty_str - }; + + if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 { + ty_str = short_ty_str; + } + if let Some(file) = ty_file { err.note(format!("the full type name has been written to '{}'", file.display(),)); } @@ -1067,6 +1080,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &static_candidates, unsatisfied_bounds, expected.only_has_type(self), + trait_missing_method, ); } @@ -2375,6 +2389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { static_candidates: &[CandidateSource], unsatisfied_bounds: bool, return_type: Option<Ty<'tcx>>, + trait_missing_method: bool, ) { let mut alt_rcvr_sugg = false; if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) { @@ -2598,11 +2613,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }, _ => None, }; - err.help(if param_type.is_some() { - "items from traits can only be used if the type parameter is bounded by the trait" - } else { - "items from traits can only be used if the trait is implemented and in scope" - }); + if !trait_missing_method { + err.help(if param_type.is_some() { + "items from traits can only be used if the type parameter is bounded by the trait" + } else { + "items from traits can only be used if the trait is implemented and in scope" + }); + } + let candidates_len = candidates.len(); let message = |action| { format!( @@ -2633,47 +2651,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Nothing, } let ast_generics = hir.get_generics(id.owner.def_id).unwrap(); - let (sp, mut introducer) = if let Some(span) = - ast_generics.bounds_span_for_suggestions(def_id) - { - (span, Introducer::Plus) - } else if let Some(colon_span) = param.colon_span { - (colon_span.shrink_to_hi(), Introducer::Nothing) - } else { - (param.span.shrink_to_hi(), Introducer::Colon) - }; - if matches!( - param.kind, - hir::GenericParamKind::Type { synthetic: true, .. }, - ) { - introducer = Introducer::Plus - } let trait_def_ids: FxHashSet<DefId> = ast_generics .bounds_for_param(def_id) .flat_map(|bp| bp.bounds.iter()) .filter_map(|bound| bound.trait_ref()?.trait_def_id()) .collect(); - if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) { - err.span_suggestions( - sp, - message(format!( - "restrict type parameter `{}` with", - param.name.ident(), - )), + if candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) { + return; + } + let msg = message(format!( + "restrict type parameter `{}` with", + param.name.ident(), + )); + let bounds_span = ast_generics.bounds_span_for_suggestions(def_id); + if rcvr_ty.is_ref() && param.is_impl_trait() && bounds_span.is_some() { + err.multipart_suggestions( + msg, candidates.iter().map(|t| { - format!( - "{} {}", - match introducer { - Introducer::Plus => " +", - Introducer::Colon => ":", - Introducer::Nothing => "", - }, - self.tcx.def_path_str(t.def_id), - ) + vec![ + (param.span.shrink_to_lo(), "(".to_string()), + ( + bounds_span.unwrap(), + format!(" + {})", self.tcx.def_path_str(t.def_id)), + ), + ] }), Applicability::MaybeIncorrect, ); + return; } + + let (sp, introducer) = if let Some(span) = bounds_span { + (span, Introducer::Plus) + } else if let Some(colon_span) = param.colon_span { + (colon_span.shrink_to_hi(), Introducer::Nothing) + } else if param.is_impl_trait() { + (param.span.shrink_to_hi(), Introducer::Plus) + } else { + (param.span.shrink_to_hi(), Introducer::Colon) + }; + + err.span_suggestions( + sp, + msg, + candidates.iter().map(|t| { + format!( + "{} {}", + match introducer { + Introducer::Plus => " +", + Introducer::Colon => ":", + Introducer::Nothing => "", + }, + self.tcx.def_path_str(t.def_id) + ) + }), + Applicability::MaybeIncorrect, + ); return; } Node::Item(hir::Item { @@ -2736,27 +2769,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (candidates, Vec::new()) }; - let action = if let Some(param) = param_type { - format!("restrict type parameter `{}` with", param) - } else { - // FIXME: it might only need to be imported into scope, not implemented. - "implement".to_string() - }; match &potential_candidates[..] { [] => {} [trait_info] if trait_info.def_id.is_local() => { - err.span_note( - self.tcx.def_span(trait_info.def_id), - format!( - "`{}` defines an item `{}`, perhaps you need to {} it", - self.tcx.def_path_str(trait_info.def_id), - item_name, - action - ), - ); + err.subdiagnostic(CandidateTraitNote { + span: self.tcx.def_span(trait_info.def_id), + trait_name: self.tcx.def_path_str(trait_info.def_id), + item_name, + action_or_ty: if trait_missing_method { + "NONE".to_string() + } else { + param_type.map_or_else( + || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented. + ToString::to_string, + ) + }, + }); } trait_infos => { - let mut msg = message(action); + let mut msg = message(param_type.map_or_else( + || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented. + |param| format!("restrict type parameter `{}` with", param), + )); for (i, trait_info) in trait_infos.iter().enumerate() { msg.push_str(&format!( "\ncandidate #{}: `{}`", diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index cf95d4f04bb..2daec205cfc 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -9,7 +9,6 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir::intravisit::{self, Visitor}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; -use rustc_infer::infer::InferCtxt; use rustc_middle::hir::place::Place as HirPlace; use rustc_middle::mir::FakeReadCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast}; @@ -237,7 +236,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { // error has been emitted. (#64638) self.fcx.tcx.ty_error_with_message( e.span, - &format!("bad index {:?} for base: `{:?}`", index, base), + format!("bad index {:?} for base: `{:?}`", index, base), ) }); let index_ty = self.fcx.resolve_vars_if_possible(index_ty); @@ -692,15 +691,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fcx_typeck_results.offset_of_data().items_in_stable_order() { let hir_id = hir::HirId { owner: common_hir_owner, local_id }; - - if cfg!(debug_assertions) && container.has_infer() { - span_bug!( - hir_id.to_span(self.fcx.tcx), - "writeback: `{:?}` has inference variables", - container - ); - }; - + let container = self.resolve(container, &hir_id); self.typeck_results.offset_of_data_mut().insert(hir_id, (container, indices.clone())); } } @@ -745,8 +736,7 @@ impl Locatable for hir::HirId { /// The Resolver. This is the type folding engine that detects /// unresolved types and so forth. struct Resolver<'cx, 'tcx> { - tcx: TyCtxt<'tcx>, - infcx: &'cx InferCtxt<'tcx>, + fcx: &'cx FnCtxt<'cx, 'tcx>, span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, @@ -760,18 +750,18 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { span: &'cx dyn Locatable, body: &'tcx hir::Body<'tcx>, ) -> Resolver<'cx, 'tcx> { - Resolver { tcx: fcx.tcx, infcx: fcx, span, body, replaced_with_error: None } + Resolver { fcx, span, body, replaced_with_error: None } } fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed { - match self.tcx.sess.has_errors() { + match self.fcx.tcx.sess.has_errors() { Some(e) => e, None => self - .infcx + .fcx .err_ctxt() .emit_inference_failure_err( - self.tcx.hir().body_owner_def_id(self.body.id()), - self.span.to_span(self.tcx), + self.fcx.tcx.hir().body_owner_def_id(self.body.id()), + self.span.to_span(self.fcx.tcx), p.into(), E0282, false, @@ -803,40 +793,46 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEarlyRegions<'tcx> { impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> { fn interner(&self) -> TyCtxt<'tcx> { - self.tcx + self.fcx.tcx } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match self.infcx.fully_resolve(t) { + match self.fcx.fully_resolve(t) { + Ok(t) if self.fcx.tcx.trait_solver_next() => { + // We must normalize erasing regions here, since later lints + // expect that types that show up in the typeck are fully + // normalized. + self.fcx.tcx.try_normalize_erasing_regions(self.fcx.param_env, t).unwrap_or(t) + } Ok(t) => { // Do not anonymize late-bound regions // (e.g. keep `for<'a>` named `for<'a>`). // This allows NLL to generate error messages that // refer to the higher-ranked lifetime names written by the user. - EraseEarlyRegions { tcx: self.tcx }.fold_ty(t) + EraseEarlyRegions { tcx: self.fcx.tcx }.fold_ty(t) } Err(_) => { debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t); let e = self.report_error(t); self.replaced_with_error = Some(e); - self.interner().ty_error(e) + self.fcx.tcx.ty_error(e) } } } fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> { debug_assert!(!r.is_late_bound(), "Should not be resolving bound region."); - self.tcx.lifetimes.re_erased + self.fcx.tcx.lifetimes.re_erased } fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { - match self.infcx.fully_resolve(ct) { - Ok(ct) => self.tcx.erase_regions(ct), + match self.fcx.fully_resolve(ct) { + Ok(ct) => self.fcx.tcx.erase_regions(ct), Err(_) => { debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct); let e = self.report_error(ct); self.replaced_with_error = Some(e); - self.interner().const_error_with_guaranteed(ct.ty(), e) + self.fcx.tcx.const_error(ct.ty(), e) } } } diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index dc981c6179e..25bf83f64a0 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -14,6 +14,7 @@ use rustc_data_structures::memmap::Mmap; use rustc_serialize::opaque::{FileEncodeResult, FileEncoder}; use rustc_serialize::Encoder; use rustc_session::Session; +use std::borrow::Cow; use std::env; use std::fs; use std::io::{self, Read}; @@ -25,17 +26,12 @@ const FILE_MAGIC: &[u8] = b"RSIC"; /// Change this if the header format changes. const HEADER_FORMAT_VERSION: u16 = 0; -/// A version string that hopefully is always different for compiler versions -/// with different encodings of incremental compilation artifacts. Contains -/// the Git commit hash. -const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION"); - -pub(crate) fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) { +pub(crate) fn write_file_header(stream: &mut FileEncoder, sess: &Session) { stream.emit_raw_bytes(FILE_MAGIC); stream .emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]); - let rustc_version = rustc_version(nightly_build); + let rustc_version = rustc_version(sess.is_nightly_build(), sess.cfg_version); assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize); stream.emit_raw_bytes(&[rustc_version.len() as u8]); stream.emit_raw_bytes(rustc_version.as_bytes()); @@ -73,7 +69,7 @@ where } }; - write_file_header(&mut encoder, sess.is_nightly_build()); + write_file_header(&mut encoder, sess); match encode(encoder) { Ok(position) => { @@ -100,9 +96,10 @@ where /// - Returns `Err(..)` if some kind of IO error occurred while reading the /// file. pub fn read_file( - report_incremental_info: bool, path: &Path, - nightly_build: bool, + report_incremental_info: bool, + is_nightly_build: bool, + cfg_version: &'static str, ) -> io::Result<Option<(Mmap, usize)>> { let file = match fs::File::open(path) { Ok(file) => file, @@ -152,7 +149,7 @@ pub fn read_file( let mut buffer = vec![0; rustc_version_str_len]; file.read_exact(&mut buffer)?; - if buffer != rustc_version(nightly_build).as_bytes() { + if buffer != rustc_version(is_nightly_build, cfg_version).as_bytes() { report_format_mismatch(report_incremental_info, path, "Different compiler version"); return Ok(None); } @@ -174,17 +171,15 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: & } } -fn rustc_version(nightly_build: bool) -> String { +/// A version string that hopefully is always different for compiler versions +/// with different encodings of incremental compilation artifacts. Contains +/// the Git commit hash. +fn rustc_version(nightly_build: bool, cfg_version: &'static str) -> Cow<'static, str> { if nightly_build { - if let Some(val) = env::var_os("RUSTC_FORCE_RUSTC_VERSION") { - return val.to_string_lossy().into_owned(); + if let Ok(val) = env::var("RUSTC_FORCE_RUSTC_VERSION") { + return val.into(); } } - RUSTC_VERSION - .expect( - "Cannot use rustc without explicit version for \ - incremental compilation", - ) - .to_string() + cfg_version.into() } diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs index ec7fcbdf884..a4407a93ff3 100644 --- a/compiler/rustc_incremental/src/persist/load.rs +++ b/compiler/rustc_incremental/src/persist/load.rs @@ -73,12 +73,22 @@ impl<T: Default> LoadResult<T> { } } -fn load_data( - report_incremental_info: bool, +fn load_data(path: &Path, sess: &Session) -> LoadResult<(Mmap, usize)> { + load_data_no_sess( + path, + sess.opts.unstable_opts.incremental_info, + sess.is_nightly_build(), + sess.cfg_version, + ) +} + +fn load_data_no_sess( path: &Path, - nightly_build: bool, + report_incremental_info: bool, + is_nightly_build: bool, + cfg_version: &'static str, ) -> LoadResult<(Mmap, usize)> { - match file_format::read_file(report_incremental_info, path, nightly_build) { + match file_format::read_file(path, report_incremental_info, is_nightly_build, cfg_version) { Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos }, Ok(None) => { // The file either didn't exist or was produced by an incompatible @@ -138,14 +148,13 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { let expected_hash = sess.opts.dep_tracking_hash(false); let mut prev_work_products = FxHashMap::default(); - let nightly_build = sess.is_nightly_build(); // If we are only building with -Zquery-dep-graph but without an actual // incr. comp. session directory, we skip this. Otherwise we'd fail // when trying to load work products. if sess.incr_comp_session_dir_opt().is_some() { let work_products_path = work_products_path(sess); - let load_result = load_data(report_incremental_info, &work_products_path, nightly_build); + let load_result = load_data(&work_products_path, sess); if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result { // Decode the list of work_products @@ -173,10 +182,13 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture { } } + let is_nightly_build = sess.is_nightly_build(); + let cfg_version = sess.cfg_version; + MaybeAsync::Async(std::thread::spawn(move || { let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph"); - match load_data(report_incremental_info, &path, nightly_build) { + match load_data_no_sess(&path, report_incremental_info, is_nightly_build, cfg_version) { LoadResult::DataOutOfDate => LoadResult::DataOutOfDate, LoadResult::LoadDepGraph(path, err) => LoadResult::LoadDepGraph(path, err), LoadResult::DecodeIncrCache(err) => LoadResult::DecodeIncrCache(err), @@ -218,11 +230,7 @@ pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> { let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache"); - match load_data( - sess.opts.unstable_opts.incremental_info, - &query_cache_path(sess), - sess.is_nightly_build(), - ) { + match load_data(&query_cache_path(sess), sess) { LoadResult::Ok { data: (bytes, start_pos) } => { Some(OnDiskCache::new(sess, bytes, start_pos)) } diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index 1441e64e41f..7376be6be8b 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -164,7 +164,7 @@ pub fn build_dep_graph( } }; - file_format::write_file_header(&mut encoder, sess.is_nightly_build()); + file_format::write_file_header(&mut encoder, sess); // First encode the commandline arguments hash sess.opts.dep_tracking_hash(false).encode(&mut encoder); diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index 3605e10fecd..de9afbbcaab 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -153,20 +153,22 @@ impl<'tcx> InferCtxt<'tcx> { /// Used by the new solver as that one takes the opaque types at the end of a probe /// to deal with multiple candidates without having to recompute them. - pub fn clone_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { + pub fn clone_opaque_types_for_query_response( + &self, + ) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { self.inner .borrow() .opaque_type_storage .opaque_types .iter() - .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) + .map(|(k, v)| (*k, v.hidden_type.ty)) .collect() } - fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> { + fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> { std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types) .into_iter() - .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty)) + .map(|(k, v)| (k, v.hidden_type.ty)) .collect() } @@ -507,8 +509,22 @@ impl<'tcx> InferCtxt<'tcx> { let a = substitute_value(self.tcx, &result_subst, a); let b = substitute_value(self.tcx, &result_subst, b); debug!(?a, ?b, "constrain opaque type"); - obligations - .extend(self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, a, b)?.obligations); + // We use equate here instead of, for example, just registering the + // opaque type's hidden value directly, because we may be instantiating + // a query response that was canonicalized in an InferCtxt that had + // a different defining anchor. In that case, we may have inferred + // `NonLocalOpaque := LocalOpaque` but can only instantiate it in + // the other direction as `LocalOpaque := NonLocalOpaque`. Using eq + // here allows us to try both directions (in `InferCtxt::handle_opaque_type`). + obligations.extend( + self.at(cause, param_env) + .eq( + DefineOpaqueTypes::Yes, + self.tcx.mk_opaque(a.def_id.to_def_id(), a.substs), + b, + )? + .obligations, + ); } Ok(InferOk { value: result_subst, obligations }) diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs index 08eec0707c0..79fc02c6c79 100644 --- a/compiler/rustc_infer/src/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -26,24 +26,17 @@ use super::equate::Equate; use super::glb::Glb; use super::lub::Lub; use super::sub::Sub; -use super::type_variable::TypeVariableValue; -use super::{DefineOpaqueTypes, InferCtxt, MiscVariable, TypeTrace}; +use super::{DefineOpaqueTypes, InferCtxt, TypeTrace}; +use crate::infer::generalize::{self, CombineDelegate, Generalization}; use crate::traits::{Obligation, PredicateObligations}; -use rustc_data_structures::sso::SsoHashMap; -use rustc_hir::def_id::DefId; use rustc_middle::infer::canonical::OriginalQueryValues; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; -use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{ - self, AliasKind, FallibleTypeFolder, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable, - TypeSuperFoldable, TypeVisitableExt, -}; +use rustc_middle::ty::relate::{RelateResult, TypeRelation}; +use rustc_middle::ty::{self, AliasKind, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{IntType, UintType}; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::DUMMY_SP; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { @@ -55,13 +48,6 @@ pub struct CombineFields<'infcx, 'tcx> { pub define_opaque_types: DefineOpaqueTypes, } -#[derive(Copy, Clone, Debug)] -pub enum RelationDir { - SubtypeOf, - SupertypeOf, - EqTo, -} - impl<'tcx> InferCtxt<'tcx> { pub fn super_combine_tys<R>( &self, @@ -152,7 +138,7 @@ impl<'tcx> InferCtxt<'tcx> { Ok(a) } - _ => ty::relate::super_relate_tys(relation, a, b), + _ => ty::relate::structurally_relate_tys(relation, a, b), } } @@ -209,13 +195,13 @@ impl<'tcx> InferCtxt<'tcx> { // HACK: equating both sides with `[const error]` eagerly prevents us // from leaving unconstrained inference vars during things like impl // matching in the solver. - let a_error = self.tcx.const_error_with_guaranteed(a.ty(), guar); + let a_error = self.tcx.const_error(a.ty(), guar); if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() { - return self.unify_const_variable(vid, a_error); + return self.unify_const_variable(vid, a_error, relation.param_env()); } - let b_error = self.tcx.const_error_with_guaranteed(b.ty(), guar); + let b_error = self.tcx.const_error(b.ty(), guar); if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() { - return self.unify_const_variable(vid, b_error); + return self.unify_const_variable(vid, b_error, relation.param_env()); } return Ok(if relation.a_is_expected() { a_error } else { b_error }); @@ -237,11 +223,11 @@ impl<'tcx> InferCtxt<'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(vid, b); + return self.unify_const_variable(vid, b, relation.param_env()); } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(vid, a); + return self.unify_const_variable(vid, a, relation.param_env()); } (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..)) if self.tcx.lazy_normalization() => @@ -252,7 +238,7 @@ impl<'tcx> InferCtxt<'tcx> { _ => {} } - ty::relate::super_relate_consts(relation, a, b) + ty::relate::structurally_relate_consts(relation, a, b) } /// Unifies the const variable `target_vid` with the given constant. @@ -294,24 +280,17 @@ impl<'tcx> InferCtxt<'tcx> { &self, target_vid: ty::ConstVid<'tcx>, ct: ty::Const<'tcx>, + param_env: ty::ParamEnv<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - let (for_universe, span) = { - let mut inner = self.inner.borrow_mut(); - let variable_table = &mut inner.const_unification_table(); - let var_value = variable_table.probe_value(target_vid); - match var_value.val { - ConstVariableValue::Known { value } => { - bug!("instantiating {:?} which has a known value {:?}", target_vid, value) - } - ConstVariableValue::Unknown { universe } => (universe, var_value.origin.span), - } - }; - let value = ct.try_fold_with(&mut ConstInferUnifier { - infcx: self, - span, - for_universe, + let span = + self.inner.borrow_mut().const_unification_table().probe_value(target_vid).origin.span; + let Generalization { value, needs_wf: _ } = generalize::generalize( + self, + &mut CombineDelegate { infcx: self, span, param_env }, + ct, target_vid, - })?; + ty::Variance::Invariant, + )?; self.inner.borrow_mut().const_unification_table().union_value( target_vid, @@ -392,12 +371,10 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { pub fn instantiate( &mut self, a_ty: Ty<'tcx>, - dir: RelationDir, + ambient_variance: ty::Variance, b_vid: ty::TyVid, a_is_expected: bool, ) -> RelateResult<'tcx, ()> { - use self::RelationDir::*; - // Get the actual variable that b_vid has been inferred to debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown()); @@ -412,7 +389,18 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { // `'?2` and `?3` are fresh region/type inference // variables. (Down below, we will relate `a_ty <: b_ty`, // adding constraints like `'x: '?2` and `?1 <: ?3`.) - let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?; + let Generalization { value: b_ty, needs_wf } = generalize::generalize( + self.infcx, + &mut CombineDelegate { + infcx: self.infcx, + param_env: self.param_env, + span: self.trace.span(), + }, + a_ty, + b_vid, + ambient_variance, + )?; + debug!(?b_ty); self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty); @@ -431,78 +419,23 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { // relations wind up attributed to the same spans. We need // to associate causes/spans with each of the relations in // the stack to get this right. - match dir { - EqTo => self.equate(a_is_expected).relate(a_ty, b_ty), - SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty), - SupertypeOf => self.sub(a_is_expected).relate_with_variance( + match ambient_variance { + ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty), + ty::Variance::Covariant => self.sub(a_is_expected).relate(a_ty, b_ty), + ty::Variance::Contravariant => self.sub(a_is_expected).relate_with_variance( ty::Contravariant, ty::VarianceDiagInfo::default(), a_ty, b_ty, ), + ty::Variance::Bivariant => { + unreachable!("no code should be generalizing bivariantly (currently)") + } }?; Ok(()) } - /// Attempts to generalize `ty` for the type variable `for_vid`. - /// This checks for cycle -- that is, whether the type `ty` - /// references `for_vid`. The `dir` is the "direction" for which we - /// a performing the generalization (i.e., are we producing a type - /// that can be used as a supertype etc). - /// - /// Preconditions: - /// - /// - `for_vid` is a "root vid" - #[instrument(skip(self), level = "trace", ret)] - fn generalize( - &self, - ty: Ty<'tcx>, - for_vid: ty::TyVid, - dir: RelationDir, - ) -> RelateResult<'tcx, Generalization<'tcx>> { - // Determine the ambient variance within which `ty` appears. - // The surrounding equation is: - // - // ty [op] ty2 - // - // where `op` is either `==`, `<:`, or `:>`. This maps quite - // naturally. - let ambient_variance = match dir { - RelationDir::EqTo => ty::Invariant, - RelationDir::SubtypeOf => ty::Covariant, - RelationDir::SupertypeOf => ty::Contravariant, - }; - - trace!(?ambient_variance); - - let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) { - v @ TypeVariableValue::Known { .. } => { - bug!("instantiating {:?} which has a known value {:?}", for_vid, v,) - } - TypeVariableValue::Unknown { universe } => universe, - }; - - trace!(?for_universe); - trace!(?self.trace); - - let mut generalize = Generalizer { - infcx: self.infcx, - cause: &self.trace.cause, - for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid), - for_universe, - ambient_variance, - needs_wf: false, - root_ty: ty, - param_env: self.param_env, - cache: SsoHashMap::new(), - }; - - let ty = generalize.relate(ty, ty)?; - let needs_wf = generalize.needs_wf; - Ok(Generalization { ty, needs_wf }) - } - pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) { self.obligations.extend(obligations.into_iter()); } @@ -514,313 +447,6 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { } } -struct Generalizer<'cx, 'tcx> { - infcx: &'cx InferCtxt<'tcx>, - - /// The span, used when creating new type variables and things. - cause: &'cx ObligationCause<'tcx>, - - /// The vid of the type variable that is in the process of being - /// instantiated; if we find this within the type we are folding, - /// that means we would have created a cyclic type. - for_vid_sub_root: ty::TyVid, - - /// The universe of the type variable that is in the process of - /// being instantiated. Any fresh variables that we create in this - /// process should be in that same universe. - for_universe: ty::UniverseIndex, - - /// Track the variance as we descend into the type. - ambient_variance: ty::Variance, - - /// See the field `needs_wf` in `Generalization`. - needs_wf: bool, - - /// The root type that we are generalizing. Used when reporting cycles. - root_ty: Ty<'tcx>, - - param_env: ty::ParamEnv<'tcx>, - - cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>, -} - -/// Result from a generalization operation. This includes -/// not only the generalized type, but also a bool flag -/// indicating whether further WF checks are needed. -#[derive(Debug)] -struct Generalization<'tcx> { - ty: Ty<'tcx>, - - /// If true, then the generalized type may not be well-formed, - /// even if the source type is well-formed, so we should add an - /// additional check to enforce that it is. This arises in - /// particular around 'bivariant' type parameters that are only - /// constrained by a where-clause. As an example, imagine a type: - /// - /// struct Foo<A, B> where A: Iterator<Item = B> { - /// data: A - /// } - /// - /// here, `A` will be covariant, but `B` is - /// unconstrained. However, whatever it is, for `Foo` to be WF, it - /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`, - /// then after generalization we will wind up with a type like - /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C, - /// ?D>` (or `>:`), we will wind up with the requirement that `?A - /// <: ?C`, but no particular relationship between `?B` and `?D` - /// (after all, we do not know the variance of the normalized form - /// of `A::Item` with respect to `A`). If we do nothing else, this - /// may mean that `?D` goes unconstrained (as in #41677). So, in - /// this scenario where we create a new type variable in a - /// bivariant context, we set the `needs_wf` flag to true. This - /// will force the calling code to check that `WF(Foo<?C, ?D>)` - /// holds, which in turn implies that `?C::Item == ?D`. So once - /// `?C` is constrained, that should suffice to restrict `?D`. - needs_wf: bool, -} - -impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn tag(&self) -> &'static str { - "Generalizer" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn binders<T>( - &mut self, - a: ty::Binder<'tcx, T>, - b: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>, - { - Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?)) - } - - fn relate_item_substs( - &mut self, - item_def_id: DefId, - a_subst: SubstsRef<'tcx>, - b_subst: SubstsRef<'tcx>, - ) -> RelateResult<'tcx, SubstsRef<'tcx>> { - if self.ambient_variance == ty::Variance::Invariant { - // Avoid fetching the variance if we are in an invariant - // context; no need, and it can induce dependency cycles - // (e.g., #41849). - relate::relate_substs(self, a_subst, b_subst) - } else { - let tcx = self.tcx(); - let opt_variances = tcx.variances_of(item_def_id); - relate::relate_substs_with_variances( - self, - item_def_id, - &opt_variances, - a_subst, - b_subst, - true, - ) - } - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - - let result = self.relate(a, b); - self.ambient_variance = old_ambient_variance; - result - } - - fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - - if let Some(&result) = self.cache.get(&t) { - return Ok(result); - } - debug!("generalize: t={:?}", t); - - // Check to see whether the type we are generalizing references - // any other type variable related to `vid` via - // subtyping. This is basically our "occurs check", preventing - // us from creating infinitely sized types. - let result = match *t.kind() { - ty::Infer(ty::TyVar(vid)) => { - let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); - let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid); - if sub_vid == self.for_vid_sub_root { - // If sub-roots are equal, then `for_vid` and - // `vid` are related via subtyping. - Err(TypeError::CyclicTy(self.root_ty)) - } else { - let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid); - match probe { - TypeVariableValue::Known { value: u } => { - debug!("generalize: known value {:?}", u); - self.relate(u, u) - } - TypeVariableValue::Unknown { universe } => { - match self.ambient_variance { - // Invariant: no need to make a fresh type variable. - ty::Invariant => { - if self.for_universe.can_name(universe) { - return Ok(t); - } - } - - // Bivariant: make a fresh var, but we - // may need a WF predicate. See - // comment on `needs_wf` field for - // more info. - ty::Bivariant => self.needs_wf = true, - - // Co/contravariant: this will be - // sufficiently constrained later on. - ty::Covariant | ty::Contravariant => (), - } - - let origin = - *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); - let new_var_id = self - .infcx - .inner - .borrow_mut() - .type_variables() - .new_var(self.for_universe, origin); - let u = self.tcx().mk_ty_var(new_var_id); - - // Record that we replaced `vid` with `new_var_id` as part of a generalization - // operation. This is needed to detect cyclic types. To see why, see the - // docs in the `type_variables` module. - self.infcx.inner.borrow_mut().type_variables().sub(vid, new_var_id); - debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); - Ok(u) - } - } - } - } - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { - // No matter what mode we are in, - // integer/floating-point types must be equal to be - // relatable. - Ok(t) - } - ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { - let s = self.relate(substs, substs)?; - Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) }) - } - _ => relate::super_relate_tys(self, t, t), - }?; - - self.cache.insert(t, result); - Ok(result) - } - - fn regions( - &mut self, - r: ty::Region<'tcx>, - r2: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - - debug!("generalize: regions r={:?}", r); - - match *r { - // Never make variables for regions bound within the type itself, - // nor for erased regions. - ty::ReLateBound(..) | ty::ReErased => { - return Ok(r); - } - - ty::ReError(_) => { - return Ok(r); - } - - ty::RePlaceholder(..) - | ty::ReVar(..) - | ty::ReStatic - | ty::ReEarlyBound(..) - | ty::ReFree(..) => { - // see common code below - } - } - - // If we are in an invariant context, we can re-use the region - // as is, unless it happens to be in some universe that we - // can't name. (In the case of a region *variable*, we could - // use it if we promoted it into our universe, but we don't - // bother.) - if let ty::Invariant = self.ambient_variance { - let r_universe = self.infcx.universe_of_region(r); - if self.for_universe.can_name(r_universe) { - return Ok(r); - } - } - - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.cause.span), self.for_universe)) - } - - fn consts( - &mut self, - c: ty::Const<'tcx>, - c2: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be == - - match c.kind() { - ty::ConstKind::Infer(InferConst::Var(vid)) => { - let mut inner = self.infcx.inner.borrow_mut(); - let variable_table = &mut inner.const_unification_table(); - let var_value = variable_table.probe_value(vid); - match var_value.val { - ConstVariableValue::Known { value: u } => { - drop(inner); - self.relate(u, u) - } - ConstVariableValue::Unknown { universe } => { - if self.for_universe.can_name(universe) { - Ok(c) - } else { - let new_var_id = variable_table.new_key(ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { universe: self.for_universe }, - }); - Ok(self.tcx().mk_const(new_var_id, c.ty())) - } - } - } - } - ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { - let substs = self.relate_with_variance( - ty::Variance::Invariant, - ty::VarianceDiagInfo::default(), - substs, - substs, - )?; - Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty())) - } - _ => relate::super_relate_consts(self, c, c), - } - } -} - pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> { /// Register obligations that must hold in order for this relation to hold fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>); @@ -873,135 +499,3 @@ fn float_unification_error<'tcx>( let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b)) } - -struct ConstInferUnifier<'cx, 'tcx> { - infcx: &'cx InferCtxt<'tcx>, - - span: Span, - - for_universe: ty::UniverseIndex, - - /// The vid of the const variable that is in the process of being - /// instantiated; if we find this within the const we are folding, - /// that means we would have created a cyclic const. - target_vid: ty::ConstVid<'tcx>, -} - -impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ConstInferUnifier<'_, 'tcx> { - type Error = TypeError<'tcx>; - - fn interner(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - #[instrument(level = "debug", skip(self), ret)] - fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, TypeError<'tcx>> { - match t.kind() { - &ty::Infer(ty::TyVar(vid)) => { - let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); - let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid); - match probe { - TypeVariableValue::Known { value: u } => { - debug!("ConstOccursChecker: known value {:?}", u); - u.try_fold_with(self) - } - TypeVariableValue::Unknown { universe } => { - if self.for_universe.can_name(universe) { - return Ok(t); - } - - let origin = - *self.infcx.inner.borrow_mut().type_variables().var_origin(vid); - let new_var_id = self - .infcx - .inner - .borrow_mut() - .type_variables() - .new_var(self.for_universe, origin); - Ok(self.interner().mk_ty_var(new_var_id)) - } - } - } - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => Ok(t), - _ => t.try_super_fold_with(self), - } - } - - #[instrument(level = "debug", skip(self), ret)] - fn try_fold_region( - &mut self, - r: ty::Region<'tcx>, - ) -> Result<ty::Region<'tcx>, TypeError<'tcx>> { - debug!("ConstInferUnifier: r={:?}", r); - - match *r { - // Never make variables for regions bound within the type itself, - // nor for erased regions. - ty::ReLateBound(..) | ty::ReErased | ty::ReError(_) => { - return Ok(r); - } - - ty::RePlaceholder(..) - | ty::ReVar(..) - | ty::ReStatic - | ty::ReEarlyBound(..) - | ty::ReFree(..) => { - // see common code below - } - } - - let r_universe = self.infcx.universe_of_region(r); - if self.for_universe.can_name(r_universe) { - return Ok(r); - } else { - // FIXME: This is non-ideal because we don't give a - // very descriptive origin for this region variable. - Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe)) - } - } - - #[instrument(level = "debug", skip(self), ret)] - fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, TypeError<'tcx>> { - match c.kind() { - ty::ConstKind::Infer(InferConst::Var(vid)) => { - // Check if the current unification would end up - // unifying `target_vid` with a const which contains - // an inference variable which is unioned with `target_vid`. - // - // Not doing so can easily result in stack overflows. - if self - .infcx - .inner - .borrow_mut() - .const_unification_table() - .unioned(self.target_vid, vid) - { - return Err(TypeError::CyclicConst(c)); - } - - let var_value = - self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid); - match var_value.val { - ConstVariableValue::Known { value: u } => u.try_fold_with(self), - ConstVariableValue::Unknown { universe } => { - if self.for_universe.can_name(universe) { - Ok(c) - } else { - let new_var_id = - self.infcx.inner.borrow_mut().const_unification_table().new_key( - ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { - universe: self.for_universe, - }, - }, - ); - Ok(self.interner().mk_const(new_var_id, c.ty())) - } - } - } - } - _ => c.try_super_fold_with(self), - } - } -} diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index f90f7674b55..793505e4ab2 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -1,7 +1,7 @@ use crate::infer::DefineOpaqueTypes; use crate::traits::PredicateObligations; -use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir}; +use super::combine::{CombineFields, ObligationEmittingRelation}; use super::Subtype; use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; @@ -88,11 +88,11 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { } (&ty::Infer(TyVar(a_id)), _) => { - self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?; + self.fields.instantiate(b, ty::Invariant, a_id, self.a_is_expected)?; } (_, &ty::Infer(TyVar(b_id))) => { - self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?; + self.fields.instantiate(a, ty::Invariant, b_id, self.a_is_expected)?; } ( diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index ce70f39cc40..ad4f5058b5e 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2723,7 +2723,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> { | (ty::Infer(ty::InferTy::TyVar(_)), _) | (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a), (ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch), - _ => relate::super_relate_tys(self, a, b), + _ => relate::structurally_relate_tys(self, a, b), } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 064811bd29d..421eb807a14 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -2,6 +2,7 @@ use super::TypeErrCtxt; use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect}; use rustc_errors::{pluralize, Diagnostic, MultiSpan}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_middle::traits::ObligationCauseCode; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::print::Printer; @@ -256,6 +257,15 @@ impl<T> Trait<T> for X { ); } } + (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => { + if tcx.is_type_alias_impl_trait(alias.def_id) { + if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) { + diag.span_note(tcx.def_span(body_owner_def_id), "\ + this item must have the opaque type in its signature \ + in order to be able to register hidden types"); + } + } + } (ty::FnPtr(_), ty::FnDef(def, _)) if let hir::def::DefKind::Fn = tcx.def_kind(def) => { diag.note( diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs new file mode 100644 index 00000000000..d4a1dacde10 --- /dev/null +++ b/compiler/rustc_infer/src/infer/generalize.rs @@ -0,0 +1,479 @@ +use rustc_data_structures::sso::SsoHashMap; +use rustc_hir::def_id::DefId; +use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; +use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::{self, InferConst, Term, Ty, TyCtxt, TypeVisitableExt}; +use rustc_span::Span; + +use crate::infer::nll_relate::TypeRelatingDelegate; +use crate::infer::type_variable::TypeVariableValue; +use crate::infer::{InferCtxt, RegionVariableOrigin}; + +/// Attempts to generalize `term` for the type variable `for_vid`. +/// This checks for cycles -- that is, whether the type `term` +/// references `for_vid`. +pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> + Relate<'tcx>>( + infcx: &InferCtxt<'tcx>, + delegate: &mut D, + term: T, + for_vid: impl Into<ty::TermVid<'tcx>>, + ambient_variance: ty::Variance, +) -> RelateResult<'tcx, Generalization<T>> { + let (for_universe, root_vid) = match for_vid.into() { + ty::TermVid::Ty(ty_vid) => ( + infcx.probe_ty_var(ty_vid).unwrap_err(), + ty::TermVid::Ty(infcx.inner.borrow_mut().type_variables().sub_root_var(ty_vid)), + ), + ty::TermVid::Const(ct_vid) => ( + infcx.probe_const_var(ct_vid).unwrap_err(), + ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid)), + ), + }; + + let mut generalizer = Generalizer { + infcx, + delegate, + ambient_variance, + root_vid, + for_universe, + root_term: term.into(), + needs_wf: false, + cache: Default::default(), + }; + + assert!(!term.has_escaping_bound_vars()); + let value = generalizer.relate(term, term)?; + let needs_wf = generalizer.needs_wf; + Ok(Generalization { value, needs_wf }) +} + +/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking +/// in the generalizer code. +pub trait GeneralizerDelegate<'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx>; + + fn forbid_inference_vars() -> bool; + + fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>; +} + +pub struct CombineDelegate<'cx, 'tcx> { + pub infcx: &'cx InferCtxt<'tcx>, + pub param_env: ty::ParamEnv<'tcx>, + pub span: Span, +} + +impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> { + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } + + fn forbid_inference_vars() -> bool { + false + } + + fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { + // FIXME: This is non-ideal because we don't give a + // very descriptive origin for this region variable. + self.infcx + .next_region_var_in_universe(RegionVariableOrigin::MiscVariable(self.span), universe) + } +} + +impl<'tcx, T> GeneralizerDelegate<'tcx> for T +where + T: TypeRelatingDelegate<'tcx>, +{ + fn param_env(&self) -> ty::ParamEnv<'tcx> { + <Self as TypeRelatingDelegate<'tcx>>::param_env(self) + } + + fn forbid_inference_vars() -> bool { + <Self as TypeRelatingDelegate<'tcx>>::forbid_inference_vars() + } + + fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> { + <Self as TypeRelatingDelegate<'tcx>>::generalize_existential(self, universe) + } +} + +/// The "generalizer" is used when handling inference variables. +/// +/// The basic strategy for handling a constraint like `?A <: B` is to +/// apply a "generalization strategy" to the term `B` -- this replaces +/// all the lifetimes in the term `B` with fresh inference variables. +/// (You can read more about the strategy in this [blog post].) +/// +/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x +/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the +/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which +/// establishes `'0: 'x` as a constraint. +/// +/// [blog post]: https://is.gd/0hKvIr +struct Generalizer<'me, 'tcx, D> { + infcx: &'me InferCtxt<'tcx>, + + /// This is used to abstract the behaviors of the three previous + /// generalizer-like implementations (`Generalizer`, `TypeGeneralizer`, + /// and `ConstInferUnifier`). See [`GeneralizerDelegate`] for more + /// information. + delegate: &'me mut D, + + /// After we generalize this type, we are going to relate it to + /// some other type. What will be the variance at this point? + ambient_variance: ty::Variance, + + /// The vid of the type variable that is in the process of being + /// instantiated. If we find this within the value we are folding, + /// that means we would have created a cyclic value. + root_vid: ty::TermVid<'tcx>, + + /// The universe of the type variable that is in the process of being + /// instantiated. If we find anything that this universe cannot name, + /// we reject the relation. + for_universe: ty::UniverseIndex, + + /// The root term (const or type) we're generalizing. Used for cycle errors. + root_term: Term<'tcx>, + + cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>, + + /// See the field `needs_wf` in `Generalization`. + needs_wf: bool, +} + +impl<'tcx, D> Generalizer<'_, 'tcx, D> { + /// Create an error that corresponds to the term kind in `root_term` + fn cyclic_term_error(&self) -> TypeError<'tcx> { + match self.root_term.unpack() { + ty::TermKind::Ty(ty) => TypeError::CyclicTy(ty), + ty::TermKind::Const(ct) => TypeError::CyclicConst(ct), + } + } +} + +impl<'tcx, D> TypeRelation<'tcx> for Generalizer<'_, 'tcx, D> +where + D: GeneralizerDelegate<'tcx>, +{ + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.delegate.param_env() + } + + fn tag(&self) -> &'static str { + "Generalizer" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_item_substs( + &mut self, + item_def_id: DefId, + a_subst: ty::SubstsRef<'tcx>, + b_subst: ty::SubstsRef<'tcx>, + ) -> RelateResult<'tcx, ty::SubstsRef<'tcx>> { + if self.ambient_variance == ty::Variance::Invariant { + // Avoid fetching the variance if we are in an invariant + // context; no need, and it can induce dependency cycles + // (e.g., #41849). + relate::relate_substs(self, a_subst, b_subst) + } else { + let tcx = self.tcx(); + let opt_variances = tcx.variances_of(item_def_id); + relate::relate_substs_with_variances( + self, + item_def_id, + opt_variances, + a_subst, + b_subst, + true, + ) + } + } + + #[instrument(level = "debug", skip(self, variance, b), ret)] + fn relate_with_variance<T: Relate<'tcx>>( + &mut self, + variance: ty::Variance, + _info: ty::VarianceDiagInfo<'tcx>, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + let old_ambient_variance = self.ambient_variance; + self.ambient_variance = self.ambient_variance.xform(variance); + debug!(?self.ambient_variance, "new ambient variance"); + let r = self.relate(a, b)?; + self.ambient_variance = old_ambient_variance; + Ok(r) + } + + #[instrument(level = "debug", skip(self, t2), ret)] + fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be == + + if let Some(&result) = self.cache.get(&t) { + return Ok(result); + } + + // Check to see whether the type we are generalizing references + // any other type variable related to `vid` via + // subtyping. This is basically our "occurs check", preventing + // us from creating infinitely sized types. + let g = match *t.kind() { + ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) + if D::forbid_inference_vars() => + { + bug!("unexpected inference variable encountered in NLL generalization: {t}"); + } + + ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { + bug!("unexpected infer type: {t}") + } + + ty::Infer(ty::TyVar(vid)) => { + let mut inner = self.infcx.inner.borrow_mut(); + let vid = inner.type_variables().root_var(vid); + let sub_vid = inner.type_variables().sub_root_var(vid); + + if ty::TermVid::Ty(sub_vid) == self.root_vid { + // If sub-roots are equal, then `root_vid` and + // `vid` are related via subtyping. + Err(self.cyclic_term_error()) + } else { + let probe = inner.type_variables().probe(vid); + match probe { + TypeVariableValue::Known { value: u } => { + drop(inner); + self.relate(u, u) + } + TypeVariableValue::Unknown { universe } => { + match self.ambient_variance { + // Invariant: no need to make a fresh type variable + // if we can name the universe. + ty::Invariant => { + if self.for_universe.can_name(universe) { + return Ok(t); + } + } + + // Bivariant: make a fresh var, but we + // may need a WF predicate. See + // comment on `needs_wf` field for + // more info. + ty::Bivariant => self.needs_wf = true, + + // Co/contravariant: this will be + // sufficiently constrained later on. + ty::Covariant | ty::Contravariant => (), + } + + let origin = *inner.type_variables().var_origin(vid); + let new_var_id = + inner.type_variables().new_var(self.for_universe, origin); + let u = self.tcx().mk_ty_var(new_var_id); + + // Record that we replaced `vid` with `new_var_id` as part of a generalization + // operation. This is needed to detect cyclic types. To see why, see the + // docs in the `type_variables` module. + inner.type_variables().sub(vid, new_var_id); + debug!("replacing original vid={:?} with new={:?}", vid, u); + Ok(u) + } + } + } + } + + ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { + // No matter what mode we are in, + // integer/floating-point types must be equal to be + // relatable. + Ok(t) + } + + ty::Placeholder(placeholder) => { + if self.for_universe.can_name(placeholder.universe) { + Ok(t) + } else { + debug!( + "root universe {:?} cannot name placeholder in universe {:?}", + self.for_universe, placeholder.universe + ); + Err(TypeError::Mismatch) + } + } + + _ => relate::structurally_relate_tys(self, t, t), + }?; + + self.cache.insert(t, g); + Ok(g) + } + + #[instrument(level = "debug", skip(self, r2), ret)] + fn regions( + &mut self, + r: ty::Region<'tcx>, + r2: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be == + + match *r { + // Never make variables for regions bound within the type itself, + // nor for erased regions. + ty::ReLateBound(..) | ty::ReErased => { + return Ok(r); + } + + // It doesn't really matter for correctness if we generalize ReError, + // since we're already on a doomed compilation path. + ty::ReError(_) => { + return Ok(r); + } + + ty::RePlaceholder(..) + | ty::ReVar(..) + | ty::ReStatic + | ty::ReEarlyBound(..) + | ty::ReFree(..) => { + // see common code below + } + } + + // If we are in an invariant context, we can re-use the region + // as is, unless it happens to be in some universe that we + // can't name. + if let ty::Invariant = self.ambient_variance { + let r_universe = self.infcx.universe_of_region(r); + if self.for_universe.can_name(r_universe) { + return Ok(r); + } + } + + Ok(self.delegate.generalize_region(self.for_universe)) + } + + #[instrument(level = "debug", skip(self, c2), ret)] + fn consts( + &mut self, + c: ty::Const<'tcx>, + c2: ty::Const<'tcx>, + ) -> RelateResult<'tcx, ty::Const<'tcx>> { + assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be == + + match c.kind() { + ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { + bug!("unexpected inference variable encountered in NLL generalization: {:?}", c); + } + ty::ConstKind::Infer(InferConst::Var(vid)) => { + // If root const vids are equal, then `root_vid` and + // `vid` are related and we'd be inferring an infinitely + // deep const. + if ty::TermVid::Const( + self.infcx.inner.borrow_mut().const_unification_table().find(vid), + ) == self.root_vid + { + return Err(self.cyclic_term_error()); + } + + let mut inner = self.infcx.inner.borrow_mut(); + let variable_table = &mut inner.const_unification_table(); + let var_value = variable_table.probe_value(vid); + match var_value.val { + ConstVariableValue::Known { value: u } => { + drop(inner); + self.relate(u, u) + } + ConstVariableValue::Unknown { universe } => { + if self.for_universe.can_name(universe) { + Ok(c) + } else { + let new_var_id = variable_table.new_key(ConstVarValue { + origin: var_value.origin, + val: ConstVariableValue::Unknown { universe: self.for_universe }, + }); + Ok(self.tcx().mk_const(new_var_id, c.ty())) + } + } + } + } + // FIXME: remove this branch once `structurally_relate_consts` is fully + // structural. + ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => { + let substs = self.relate_with_variance( + ty::Variance::Invariant, + ty::VarianceDiagInfo::default(), + substs, + substs, + )?; + Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty())) + } + ty::ConstKind::Placeholder(placeholder) => { + if self.for_universe.can_name(placeholder.universe) { + Ok(c) + } else { + debug!( + "root universe {:?} cannot name placeholder in universe {:?}", + self.for_universe, placeholder.universe + ); + Err(TypeError::Mismatch) + } + } + _ => relate::structurally_relate_consts(self, c, c), + } + } + + #[instrument(level = "debug", skip(self), ret)] + fn binders<T>( + &mut self, + a: ty::Binder<'tcx, T>, + _: ty::Binder<'tcx, T>, + ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> + where + T: Relate<'tcx>, + { + let result = self.relate(a.skip_binder(), a.skip_binder())?; + Ok(a.rebind(result)) + } +} + +/// Result from a generalization operation. This includes +/// not only the generalized type, but also a bool flag +/// indicating whether further WF checks are needed. +#[derive(Debug)] +pub struct Generalization<T> { + pub value: T, + + /// If true, then the generalized type may not be well-formed, + /// even if the source type is well-formed, so we should add an + /// additional check to enforce that it is. This arises in + /// particular around 'bivariant' type parameters that are only + /// constrained by a where-clause. As an example, imagine a type: + /// + /// struct Foo<A, B> where A: Iterator<Item = B> { + /// data: A + /// } + /// + /// here, `A` will be covariant, but `B` is + /// unconstrained. However, whatever it is, for `Foo` to be WF, it + /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`, + /// then after generalization we will wind up with a type like + /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C, + /// ?D>` (or `>:`), we will wind up with the requirement that `?A + /// <: ?C`, but no particular relationship between `?B` and `?D` + /// (after all, we do not know the variance of the normalized form + /// of `A::Item` with respect to `A`). If we do nothing else, this + /// may mean that `?D` goes unconstrained (as in #41677). So, in + /// this scenario where we create a new type variable in a + /// bivariant context, we set the `needs_wf` flag to true. This + /// will force the calling code to check that `WF(Foo<?C, ?D>)` + /// holds, which in turn implies that `?C::Item == ?D`. So once + /// `?C` is constrained, that should suffice to restrict `?D`. + pub needs_wf: bool, +} diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 9a95a9c8375..f8329965c43 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -58,6 +58,7 @@ pub mod error_reporting; pub mod free_regions; mod freshen; mod fudge; +mod generalize; mod glb; mod higher_ranked; pub mod lattice; @@ -1533,7 +1534,7 @@ impl<'tcx> InferCtxt<'tcx> { if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? { let ct = tcx.expand_abstract_consts(ct.subst(tcx, substs)); if let Err(e) = ct.error_reported() { - return Err(ErrorHandled::Reported(e)); + return Err(ErrorHandled::Reported(e.into())); } else if ct.has_non_region_infer() || ct.has_non_region_param() { return Err(ErrorHandled::TooGeneric); } else { diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index 88a0a81e276..4ae6af5f5be 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -21,21 +21,20 @@ //! thing we relate in chalk are basically domain goals and their //! constituents) -use crate::infer::InferCtxt; -use crate::infer::{ConstVarValue, ConstVariableValue}; -use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; -use crate::traits::{Obligation, PredicateObligations}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::traits::ObligationCause; -use rustc_middle::ty::error::TypeError; use rustc_middle::ty::fold::FnMutDelegate; -use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; +use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation}; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::{self, InferConst, Ty, TyCtxt}; use rustc_span::{Span, Symbol}; use std::fmt::Debug; -use super::combine::ObligationEmittingRelation; +use crate::infer::combine::ObligationEmittingRelation; +use crate::infer::generalize::{self, Generalization}; +use crate::infer::InferCtxt; +use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind}; +use crate::traits::{Obligation, PredicateObligations}; pub struct TypeRelating<'me, 'tcx, D> where @@ -198,7 +197,7 @@ where _ => (), } - let generalized_ty = self.generalize_value(value_ty, vid)?; + let generalized_ty = self.generalize(value_ty, vid)?; debug!("relate_ty_var: generalized_ty = {:?}", generalized_ty); if D::forbid_inference_vars() { @@ -217,26 +216,15 @@ where result } - fn generalize_value<T: Relate<'tcx>>( - &mut self, - value: T, - for_vid: ty::TyVid, - ) -> RelateResult<'tcx, T> { - let universe = self.infcx.probe_ty_var(for_vid).unwrap_err(); - - if value.has_escaping_bound_vars() { - bug!("trying to instantiate {for_vid:?} with escaping bound vars: {value:?}"); - } - - let mut generalizer = TypeGeneralizer { - infcx: self.infcx, - delegate: &mut self.delegate, - ambient_variance: self.ambient_variance, - for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid), - universe, - }; - - generalizer.relate(value, value) + fn generalize(&mut self, ty: Ty<'tcx>, for_vid: ty::TyVid) -> RelateResult<'tcx, Ty<'tcx>> { + let Generalization { value: ty, needs_wf: _ } = generalize::generalize( + self.infcx, + &mut self.delegate, + ty, + for_vid, + self.ambient_variance, + )?; + Ok(ty) } fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { @@ -716,235 +704,3 @@ where })]); } } - -/// The "type generalizer" is used when handling inference variables. -/// -/// The basic strategy for handling a constraint like `?A <: B` is to -/// apply a "generalization strategy" to the type `B` -- this replaces -/// all the lifetimes in the type `B` with fresh inference -/// variables. (You can read more about the strategy in this [blog -/// post].) -/// -/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x -/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the -/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which -/// establishes `'0: 'x` as a constraint. -/// -/// [blog post]: https://is.gd/0hKvIr -struct TypeGeneralizer<'me, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - infcx: &'me InferCtxt<'tcx>, - - delegate: &'me mut D, - - /// After we generalize this type, we are going to relate it to - /// some other type. What will be the variance at this point? - ambient_variance: ty::Variance, - - /// The vid of the type variable that is in the process of being - /// instantiated. If we find this within the value we are folding, - /// that means we would have created a cyclic value. - for_vid_sub_root: ty::TyVid, - - /// The universe of the type variable that is in the process of being - /// instantiated. If we find anything that this universe cannot name, - /// we reject the relation. - universe: ty::UniverseIndex, -} - -impl<'tcx, D> TypeRelation<'tcx> for TypeGeneralizer<'_, 'tcx, D> -where - D: TypeRelatingDelegate<'tcx>, -{ - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.delegate.param_env() - } - - fn tag(&self) -> &'static str { - "nll::generalizer" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn relate_with_variance<T: Relate<'tcx>>( - &mut self, - variance: ty::Variance, - _info: ty::VarianceDiagInfo<'tcx>, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - debug!( - "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})", - variance, a, b - ); - - let old_ambient_variance = self.ambient_variance; - self.ambient_variance = self.ambient_variance.xform(variance); - - debug!( - "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}", - self.ambient_variance - ); - - let r = self.relate(a, b)?; - - self.ambient_variance = old_ambient_variance; - - debug!("TypeGeneralizer::relate_with_variance: r={:?}", r); - - Ok(r) - } - - fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - use crate::infer::type_variable::TypeVariableValue; - - debug!("TypeGeneralizer::tys(a={:?})", a); - - match *a.kind() { - ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) - if D::forbid_inference_vars() => - { - bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); - } - - ty::Infer(ty::TyVar(vid)) => { - let mut inner = self.infcx.inner.borrow_mut(); - let variables = &mut inner.type_variables(); - let vid = variables.root_var(vid); - let sub_vid = variables.sub_root_var(vid); - if sub_vid == self.for_vid_sub_root { - // If sub-roots are equal, then `for_vid` and - // `vid` are related via subtyping. - debug!("TypeGeneralizer::tys: occurs check failed"); - Err(TypeError::Mismatch) - } else { - match variables.probe(vid) { - TypeVariableValue::Known { value: u } => { - drop(variables); - self.relate(u, u) - } - TypeVariableValue::Unknown { universe: _universe } => { - if self.ambient_variance == ty::Bivariant { - // FIXME: we may need a WF predicate (related to #54105). - } - - let origin = *variables.var_origin(vid); - - // Replacing with a new variable in the universe `self.universe`, - // it will be unified later with the original type variable in - // the universe `_universe`. - let new_var_id = variables.new_var(self.universe, origin); - - let u = self.tcx().mk_ty_var(new_var_id); - debug!("generalize: replacing original vid={:?} with new={:?}", vid, u); - Ok(u) - } - } - } - } - - ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => { - // No matter what mode we are in, - // integer/floating-point types must be equal to be - // relatable. - Ok(a) - } - - ty::Placeholder(placeholder) => { - if self.universe.cannot_name(placeholder.universe) { - debug!( - "TypeGeneralizer::tys: root universe {:?} cannot name\ - placeholder in universe {:?}", - self.universe, placeholder.universe - ); - Err(TypeError::Mismatch) - } else { - Ok(a) - } - } - - _ => relate::super_relate_tys(self, a, a), - } - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - _: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - debug!("TypeGeneralizer::regions(a={:?})", a); - - if let ty::ReLateBound(..) = *a { - return Ok(a); - } - - // For now, we just always create a fresh region variable to - // replace all the regions in the source type. In the main - // type checker, we special case the case where the ambient - // variance is `Invariant` and try to avoid creating a fresh - // region variable, but since this comes up so much less in - // NLL (only when users use `_` etc) it is much less - // important. - // - // As an aside, since these new variables are created in - // `self.universe` universe, this also serves to enforce the - // universe scoping rules. - // - // FIXME(#54105) -- if the ambient variance is bivariant, - // though, we may however need to check well-formedness or - // risk a problem like #41677 again. - let replacement_region_vid = self.delegate.generalize_existential(self.universe); - - Ok(replacement_region_vid) - } - - fn consts( - &mut self, - a: ty::Const<'tcx>, - _: ty::Const<'tcx>, - ) -> RelateResult<'tcx, ty::Const<'tcx>> { - match a.kind() { - ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => { - bug!("unexpected inference variable encountered in NLL generalization: {:?}", a); - } - ty::ConstKind::Infer(InferConst::Var(vid)) => { - let mut inner = self.infcx.inner.borrow_mut(); - let variable_table = &mut inner.const_unification_table(); - let var_value = variable_table.probe_value(vid); - match var_value.val.known() { - Some(u) => self.relate(u, u), - None => { - let new_var_id = variable_table.new_key(ConstVarValue { - origin: var_value.origin, - val: ConstVariableValue::Unknown { universe: self.universe }, - }); - Ok(self.tcx().mk_const(new_var_id, a.ty())) - } - } - } - ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(a), - _ => relate::super_relate_consts(self, a, a), - } - } - - fn binders<T>( - &mut self, - a: ty::Binder<'tcx, T>, - _: ty::Binder<'tcx, T>, - ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> - where - T: Relate<'tcx>, - { - debug!("TypeGeneralizer::binders(a={:?})", a); - let result = self.relate(a.skip_binder(), a.skip_binder())?; - Ok(a.rebind(result)) - } -} diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 362b22b23a8..b88ba04b273 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -149,7 +149,7 @@ impl<'tcx> InferCtxt<'tcx> { // no one encounters it in practice. // It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`, // where it is of no concern, so we only check for TAITs. - if let Some(OpaqueTyOrigin::TyAlias) = + if let Some(OpaqueTyOrigin::TyAlias { .. }) = b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id)) { self.tcx.sess.emit_err(OpaqueHiddenTypeDiag { @@ -381,8 +381,12 @@ impl<'tcx> InferCtxt<'tcx> { // Anonymous `impl Trait` hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id, // Named `type Foo = impl Bar;` - hir::OpaqueTyOrigin::TyAlias => { - may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id) + hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => { + if in_assoc_ty { + self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id) + } else { + may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id) + } } }; in_definition_scope.then_some(origin) @@ -526,19 +530,18 @@ impl<'tcx> InferCtxt<'tcx> { // these are the same span, but not in cases like `-> (impl // Foo, impl Bar)`. let span = cause.span; - - let mut obligations = vec![]; let prev = self.inner.borrow_mut().opaque_types().register( OpaqueTypeKey { def_id, substs }, OpaqueHiddenType { ty: hidden_ty, span }, origin, ); - if let Some(prev) = prev { - obligations = self - .at(&cause, param_env) + let mut obligations = if let Some(prev) = prev { + self.at(&cause, param_env) .eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)? - .obligations; - } + .obligations + } else { + Vec::new() + }; let item_bounds = tcx.explicit_item_bounds(def_id); diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 75ce0f83fd6..cd2462d3c31 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -187,7 +187,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { } else if pattern == value { Ok(pattern) } else { - relate::super_relate_tys(self, pattern, value) + relate::structurally_relate_tys(self, pattern, value) } } @@ -201,7 +201,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { if pattern == value { Ok(pattern) } else { - relate::super_relate_consts(self, pattern, value) + relate::structurally_relate_consts(self, pattern, value) } } diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs index 3766c250a9c..e0f29a8de8f 100644 --- a/compiler/rustc_infer/src/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -1,4 +1,4 @@ -use super::combine::{CombineFields, RelationDir}; +use super::combine::CombineFields; use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin}; use crate::traits::{Obligation, PredicateObligations}; @@ -108,11 +108,11 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> { Ok(a) } (&ty::Infer(TyVar(a_id)), _) => { - self.fields.instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?; + self.fields.instantiate(b, ty::Contravariant, a_id, !self.a_is_expected)?; Ok(a) } (_, &ty::Infer(TyVar(b_id))) => { - self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?; + self.fields.instantiate(a, ty::Covariant, b_id, self.a_is_expected)?; Ok(a) } diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs index 51354c2b127..681819703c2 100644 --- a/compiler/rustc_interface/src/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -9,6 +9,7 @@ use rustc_data_structures::OnDrop; use rustc_errors::registry::Registry; use rustc_errors::{ErrorGuaranteed, Handler}; use rustc_lint::LintStore; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::{bug, ty}; use rustc_parse::maybe_new_parser_from_source_str; use rustc_query_impl::QueryCtxt; @@ -37,8 +38,7 @@ pub struct Compiler { pub(crate) sess: Lrc<Session>, codegen_backend: Lrc<Box<dyn CodegenBackend>>, pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>, - pub(crate) override_queries: - Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>, + pub(crate) override_queries: Option<fn(&Session, &mut Providers, &mut ExternProviders)>, } impl Compiler { @@ -60,6 +60,11 @@ impl Compiler { } } +#[allow(rustc::bad_opt_access)] +pub fn set_thread_safe_mode(sopts: &config::UnstableOptions) { + rustc_data_structures::sync::set_dyn_thread_safe_mode(sopts.threads > 1); +} + /// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`. pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> { rustc_span::create_default_session_if_not_set_then(move |_| { @@ -75,7 +80,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String ($reason: expr) => { early_error( ErrorOutputType::default(), - &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s), + format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s), ); }; } @@ -134,10 +139,7 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg { ($reason: expr) => { early_error( ErrorOutputType::default(), - &format!( - concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), - s - ), + format!(concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), s), ) }; } @@ -270,8 +272,7 @@ pub struct Config { /// the list of queries. /// /// The second parameter is local providers and the third parameter is external providers. - pub override_queries: - Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>, + pub override_queries: Option<fn(&Session, &mut Providers, &mut ExternProviders)>, /// This is a callback from the driver that is called to create a codegen backend. pub make_codegen_backend: @@ -347,7 +348,7 @@ pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) { // state if it was responsible for triggering the panic. let i = ty::tls::with_context_opt(|icx| { if let Some(icx) = icx { - print_query_stack(QueryCtxt { tcx: icx.tcx }, icx.query, handler, num_frames) + print_query_stack(QueryCtxt::new(icx.tcx), icx.query, handler, num_frames) } else { 0 } diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 48401eabd1e..42d8d228091 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -17,7 +17,7 @@ use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintSto use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; -use rustc_middle::ty::query::{ExternProviders, Providers}; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt}; use rustc_mir_build as mir_build; use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr}; @@ -89,6 +89,7 @@ pub fn register_plugins<'a>( crate_name, sess.crate_types().contains(&CrateType::Executable), sess.opts.cg.metadata.clone(), + sess.cfg_version, ); sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized"); rustc_incremental::prepare_session_directory(sess, crate_name, stable_crate_id)?; @@ -486,6 +487,11 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P files.push(normalize_path(profile_sample.as_path().to_path_buf())); } + // Debugger visualizer files + for debugger_visualizer in tcx.debugger_visualizers(LOCAL_CRATE) { + files.push(normalize_path(debugger_visualizer.path.clone().unwrap())); + } + if sess.binary_dep_depinfo() { if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend { if backend.contains('.') { @@ -691,6 +697,8 @@ pub fn create_global_ctxt<'tcx>( callback(sess, &mut local_providers, &mut extern_providers); } + let incremental = dep_graph.is_fully_enabled(); + sess.time("setup_global_ctxt", || { gcx_cell.get_or_init(move || { TyCtxt::create_global_ctxt( @@ -700,9 +708,13 @@ pub fn create_global_ctxt<'tcx>( hir_arena, untracked, dep_graph, - query_result_on_disk_cache, rustc_query_impl::query_callbacks(arena), - rustc_query_impl::query_system_fns(local_providers, extern_providers), + rustc_query_impl::query_system( + local_providers, + extern_providers, + query_result_on_disk_cache, + incremental, + ), ) }) }) diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs index 1c58caa0353..2c8014d8b3a 100644 --- a/compiler/rustc_interface/src/proc_macro_decls.rs +++ b/compiler/rustc_interface/src/proc_macro_decls.rs @@ -1,6 +1,6 @@ use rustc_ast::attr; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::sym; diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 6483d51a0b9..c441a8ffd6f 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -369,7 +369,7 @@ impl Linker { if sess.opts.unstable_opts.no_link { let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT); - CodegenResults::serialize_rlink(&rlink_file, &codegen_results) + CodegenResults::serialize_rlink(sess, &rlink_file, &codegen_results) .map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?; return Ok(()); } diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs index 1bae771e373..28e719a40e5 100644 --- a/compiler/rustc_interface/src/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -52,7 +52,8 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { output_file: None, temps_dir, }; - let sess = build_session(sessopts, io, None, registry, vec![], Default::default(), None, None); + let sess = + build_session(sessopts, io, None, registry, vec![], Default::default(), None, None, ""); (sess, cfg) } diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs index 8d37b1053d8..cb19750203e 100644 --- a/compiler/rustc_interface/src/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -88,7 +88,7 @@ pub fn create_session( ) { Ok(bundle) => bundle, Err(e) => { - early_error(sopts.error_format, &format!("failed to load fluent bundle: {e}")); + early_error(sopts.error_format, format!("failed to load fluent bundle: {e}")); } }; @@ -104,6 +104,7 @@ pub fn create_session( lint_caps, file_loader, target_override, + rustc_version_str().unwrap_or("unknown"), ); codegen_backend.init(&sess); @@ -220,13 +221,13 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>( fn load_backend_from_dylib(path: &Path) -> MakeBackendFn { let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| { let err = format!("couldn't load codegen backend {path:?}: {err}"); - early_error(ErrorOutputType::default(), &err); + early_error(ErrorOutputType::default(), err); }); let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") } .unwrap_or_else(|e| { let err = format!("couldn't load codegen backend: {e}"); - early_error(ErrorOutputType::default(), &err); + early_error(ErrorOutputType::default(), err); }); // Intentionally leak the dynamic library. We can't ever unload it @@ -320,7 +321,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M "failed to find a `codegen-backends` folder \ in the sysroot candidates:\n* {candidates}" ); - early_error(ErrorOutputType::default(), &err); + early_error(ErrorOutputType::default(), err); }); info!("probing {} for a codegen backend", sysroot.display()); @@ -331,7 +332,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M sysroot.display(), e ); - early_error(ErrorOutputType::default(), &err); + early_error(ErrorOutputType::default(), err); }); let mut file: Option<PathBuf> = None; @@ -359,7 +360,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M prev.display(), path.display() ); - early_error(ErrorOutputType::default(), &err); + early_error(ErrorOutputType::default(), err); } file = Some(path.clone()); } @@ -368,7 +369,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M Some(ref s) => load_backend_from_dylib(s), None => { let err = format!("unsupported builtin codegen backend `{backend_name}`"); - early_error(ErrorOutputType::default(), &err); + early_error(ErrorOutputType::default(), err); } } } diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs index c07dc19a0ac..d511d2b1280 100644 --- a/compiler/rustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -582,34 +582,38 @@ impl Cursor<'_> { let mut base = Base::Decimal; if first_digit == '0' { // Attempt to parse encoding base. - let has_digits = match self.first() { + match self.first() { 'b' => { base = Base::Binary; self.bump(); - self.eat_decimal_digits() + if !self.eat_decimal_digits() { + return Int { base, empty_int: true }; + } } 'o' => { base = Base::Octal; self.bump(); - self.eat_decimal_digits() + if !self.eat_decimal_digits() { + return Int { base, empty_int: true }; + } } 'x' => { base = Base::Hexadecimal; self.bump(); - self.eat_hexadecimal_digits() + if !self.eat_hexadecimal_digits() { + return Int { base, empty_int: true }; + } } - // Not a base prefix. - '0'..='9' | '_' | '.' | 'e' | 'E' => { + // Not a base prefix; consume additional digits. + '0'..='9' | '_' => { self.eat_decimal_digits(); - true } + + // Also not a base prefix; nothing more to do here. + '.' | 'e' | 'E' => {} + // Just a 0. _ => return Int { base, empty_int: false }, - }; - // Base prefix was provided, but there were no digits - // after it, e.g. "0x". - if !has_digits { - return Int { base, empty_int: true }; } } else { // No base prefix, parse number in the usual way. diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index 71cf644eb50..e1658d3ff82 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -520,3 +520,19 @@ lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its ass .specifically = this associated type bound is unsatisfied for `{$proj_ty}` lint_opaque_hidden_inferred_bound_sugg = add this bound + +lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing + .label = argument has type `{$arg_ty}` + .note = use `let _ = ...` to ignore the expression or result + +lint_dropping_copy_types = calls to `std::mem::drop` with a value that implements `Copy` does nothing + .label = argument has type `{$arg_ty}` + .note = use `let _ = ...` to ignore the expression or result + +lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing + .label = argument has type `{$arg_ty}` + .note = use `let _ = ...` to ignore the expression or result + +lint_forgetting_copy_types = calls to `std::mem::forget` with a value that implements `Copy` does nothing + .label = argument has type `{$arg_ty}` + .note = use `let _ = ...` to ignore the expression or result diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index b1c45eaf601..6601a80920b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -611,7 +611,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { declare_lint! { /// The `missing_copy_implementations` lint detects potentially-forgotten - /// implementations of [`Copy`]. + /// implementations of [`Copy`] for public types. /// /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html /// @@ -647,7 +647,9 @@ declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS]) impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) { + if !(cx.effective_visibilities.is_reachable(item.owner_id.def_id) + && cx.tcx.local_visibility(item.owner_id.def_id).is_public()) + { return; } let (def, ty) = match item.kind { @@ -727,7 +729,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { declare_lint! { /// The `missing_debug_implementations` lint detects missing - /// implementations of [`fmt::Debug`]. + /// implementations of [`fmt::Debug`] for public types. /// /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html /// @@ -766,7 +768,9 @@ impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]); impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) { - if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) { + if !(cx.effective_visibilities.is_reachable(item.owner_id.def_id) + && cx.tcx.local_visibility(item.owner_id.def_id).is_public()) + { return; } diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 53d7cf74cde..1d0c43e95e0 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -49,9 +49,9 @@ use std::cell::Cell; use std::iter; use std::slice; -type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync; +type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync; type LateLintPassFactory = - dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::Send + sync::Sync; + dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync; /// Information about the registered lints. /// @@ -169,7 +169,7 @@ impl LintStore { pub fn register_early_pass( &mut self, - pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync, + pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync, ) { self.early_passes.push(Box::new(pass)); } @@ -182,7 +182,7 @@ impl LintStore { /// * See [rust-clippy#5518](https://github.com/rust-lang/rust-clippy/pull/5518) pub fn register_pre_expansion_pass( &mut self, - pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync, + pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync, ) { self.pre_expansion_passes.push(Box::new(pass)); } @@ -191,8 +191,8 @@ impl LintStore { &mut self, pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + 'static - + sync::Send - + sync::Sync, + + sync::DynSend + + sync::DynSync, ) { self.late_passes.push(Box::new(pass)); } @@ -201,8 +201,8 @@ impl LintStore { &mut self, pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + 'static - + sync::Send - + sync::Sync, + + sync::DynSend + + sync::DynSync, ) { self.late_module_passes.push(Box::new(pass)); } diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs new file mode 100644 index 00000000000..ed2b384805e --- /dev/null +++ b/compiler/rustc_lint/src/drop_forget_useless.rs @@ -0,0 +1,164 @@ +use rustc_hir::{Arm, Expr, ExprKind, Node}; +use rustc_span::sym; + +use crate::{ + lints::{DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag}, + LateContext, LateLintPass, LintContext, +}; + +declare_lint! { + /// The `dropping_references` lint checks for calls to `std::mem::drop` with a reference + /// instead of an owned value. + /// + /// ### Example + /// + /// ```rust + /// # fn operation_that_requires_mutex_to_be_unlocked() {} // just to make it compile + /// # let mutex = std::sync::Mutex::new(1); // just to make it compile + /// let mut lock_guard = mutex.lock(); + /// std::mem::drop(&lock_guard); // Should have been drop(lock_guard), mutex + /// // still locked + /// operation_that_requires_mutex_to_be_unlocked(); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Calling `drop` on a reference will only drop the + /// reference itself, which is a no-op. It will not call the `drop` method (from + /// the `Drop` trait implementation) on the underlying referenced value, which + /// is likely what was intended. + pub DROPPING_REFERENCES, + Warn, + "calls to `std::mem::drop` with a reference instead of an owned value" +} + +declare_lint! { + /// The `forgetting_references` lint checks for calls to `std::mem::forget` with a reference + /// instead of an owned value. + /// + /// ### Example + /// + /// ```rust + /// let x = Box::new(1); + /// std::mem::forget(&x); // Should have been forget(x), x will still be dropped + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Calling `forget` on a reference will only forget the + /// reference itself, which is a no-op. It will not forget the underlying + /// referenced value, which is likely what was intended. + pub FORGETTING_REFERENCES, + Warn, + "calls to `std::mem::forget` with a reference instead of an owned value" +} + +declare_lint! { + /// The `dropping_copy_types` lint checks for calls to `std::mem::drop` with a value + /// that derives the Copy trait. + /// + /// ### Example + /// + /// ```rust + /// let x: i32 = 42; // i32 implements Copy + /// std::mem::drop(x); // A copy of x is passed to the function, leaving the + /// // original unaffected + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Calling `std::mem::drop` [does nothing for types that + /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the + /// value will be copied and moved into the function on invocation. + pub DROPPING_COPY_TYPES, + Warn, + "calls to `std::mem::drop` with a value that implements Copy" +} + +declare_lint! { + /// The `forgetting_copy_types` lint checks for calls to `std::mem::forget` with a value + /// that derives the Copy trait. + /// + /// ### Example + /// + /// ```rust + /// let x: i32 = 42; // i32 implements Copy + /// std::mem::forget(x); // A copy of x is passed to the function, leaving the + /// // original unaffected + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Calling `std::mem::forget` [does nothing for types that + /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the + /// value will be copied and moved into the function on invocation. + /// + /// An alternative, but also valid, explanation is that Copy types do not + /// implement the Drop trait, which means they have no destructors. Without a + /// destructor, there is nothing for `std::mem::forget` to ignore. + pub FORGETTING_COPY_TYPES, + Warn, + "calls to `std::mem::forget` with a value that implements Copy" +} + +declare_lint_pass!(DropForgetUseless => [DROPPING_REFERENCES, FORGETTING_REFERENCES, DROPPING_COPY_TYPES, FORGETTING_COPY_TYPES]); + +impl<'tcx> LateLintPass<'tcx> for DropForgetUseless { + fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { + if let ExprKind::Call(path, [arg]) = expr.kind + && let ExprKind::Path(ref qpath) = path.kind + && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id() + && let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id) + { + let arg_ty = cx.typeck_results().expr_ty(arg); + let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env); + let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); + match fn_name { + sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => { + cx.emit_spanned_lint(DROPPING_REFERENCES, expr.span, DropRefDiag { arg_ty, label: arg.span }); + }, + sym::mem_forget if arg_ty.is_ref() => { + cx.emit_spanned_lint(FORGETTING_REFERENCES, expr.span, ForgetRefDiag { arg_ty, label: arg.span }); + }, + sym::mem_drop if is_copy && !drop_is_single_call_in_arm => { + cx.emit_spanned_lint(DROPPING_COPY_TYPES, expr.span, DropCopyDiag { arg_ty, label: arg.span }); + } + sym::mem_forget if is_copy => { + cx.emit_spanned_lint(FORGETTING_COPY_TYPES, expr.span, ForgetCopyDiag { arg_ty, label: arg.span }); + } + _ => return, + }; + } + } +} + +// Dropping returned value of a function, as in the following snippet is considered idiomatic, see +// rust-lang/rust-clippy#9482 for examples. +// +// ``` +// match <var> { +// <pat> => drop(fn_with_side_effect_and_returning_some_value()), +// .. +// } +// ``` +fn is_single_call_in_arm<'tcx>( + cx: &LateContext<'tcx>, + arg: &'tcx Expr<'_>, + drop_expr: &'tcx Expr<'_>, +) -> bool { + if matches!(arg.kind, ExprKind::Call(..) | ExprKind::MethodCall(..)) { + let parent_node = cx.tcx.hir().find_parent(drop_expr.hir_id); + if let Some(Node::Arm(Arm { body, .. })) = &parent_node { + return body.hir_id == drop_expr.hir_id; + } + } + false +} diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs index e9eb14ea188..b1266b58a61 100644 --- a/compiler/rustc_lint/src/expect.rs +++ b/compiler/rustc_lint/src/expect.rs @@ -1,5 +1,5 @@ use crate::lints::{Expectation, ExpectationNote}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS; use rustc_session::lint::LintExpectationId; diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index b42878a02ee..c9781a72704 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -16,7 +16,7 @@ use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore}; use rustc_ast as ast; -use rustc_data_structures::sync::join; +use rustc_data_structures::sync::{join, DynSend}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit as hir_visit; @@ -429,7 +429,7 @@ fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>( /// Performs lint checking on a crate. pub fn check_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>( tcx: TyCtxt<'tcx>, - builtin_lints: impl FnOnce() -> T + Send, + builtin_lints: impl FnOnce() -> T + Send + DynSend, ) { join( || { diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index a43c09a7939..b92ed11f38a 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -20,7 +20,7 @@ use rustc_middle::lint::{ reveal_actual_level, struct_lint_level, LevelAndSource, LintExpectation, LintLevelSource, ShallowLintLevelMap, }; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{RegisteredTools, TyCtxt}; use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES}; use rustc_session::lint::{ diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 319eb2ea445..dfddfe09ab3 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -52,6 +52,7 @@ mod array_into_iter; pub mod builtin; mod context; mod deref_into_dyn_supertrait; +mod drop_forget_useless; mod early; mod enum_intrinsics_non_enums; mod errors; @@ -85,7 +86,7 @@ use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::{ BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS, @@ -96,6 +97,7 @@ use rustc_span::Span; use array_into_iter::ArrayIntoIter; use builtin::*; use deref_into_dyn_supertrait::*; +use drop_forget_useless::*; use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums; use for_loops_over_fallibles::*; use hidden_unicode_codepoints::*; @@ -201,6 +203,7 @@ late_lint_methods!( [ ForLoopsOverFallibles: ForLoopsOverFallibles, DerefIntoDynSupertrait: DerefIntoDynSupertrait, + DropForgetUseless: DropForgetUseless, HardwiredLints: HardwiredLints, ImproperCTypesDeclarations: ImproperCTypesDeclarations, ImproperCTypesDefinitions: ImproperCTypesDefinitions, diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index d7bacc6485f..de1c2be2875 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -662,6 +662,43 @@ pub struct ForLoopsOverFalliblesSuggestion<'a> { pub end_span: Span, } +// drop_forget_useless.rs +#[derive(LintDiagnostic)] +#[diag(lint_dropping_references)] +#[note] +pub struct DropRefDiag<'a> { + pub arg_ty: Ty<'a>, + #[label] + pub label: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_dropping_copy_types)] +#[note] +pub struct DropCopyDiag<'a> { + pub arg_ty: Ty<'a>, + #[label] + pub label: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_forgetting_references)] +#[note] +pub struct ForgetRefDiag<'a> { + pub arg_ty: Ty<'a>, + #[label] + pub label: Span, +} + +#[derive(LintDiagnostic)] +#[diag(lint_forgetting_copy_types)] +#[note] +pub struct ForgetCopyDiag<'a> { + pub arg_ty: Ty<'a>, + #[label] + pub label: Span, +} + // hidden_unicode_codepoints.rs #[derive(LintDiagnostic)] #[diag(lint_hidden_unicode_codepoints)] diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index eb175e96997..0fe140e08d2 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -103,8 +103,10 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { && let ty = cx.typeck_results().expr_ty(&await_expr) && let ty::Alias(ty::Opaque, ty::AliasTy { def_id: future_def_id, .. }) = ty.kind() && cx.tcx.ty_is_opaque_future(ty) - // FIXME: This also includes non-async fns that return `impl Future`. && let async_fn_def_id = cx.tcx.parent(*future_def_id) + && matches!(cx.tcx.def_kind(async_fn_def_id), DefKind::Fn | DefKind::AssocFn) + // Check that this `impl Future` actually comes from an `async fn` + && cx.tcx.asyncness(async_fn_def_id).is_async() && check_must_use_def( cx, async_fn_def_id, diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 5ec3b95225d..c43a0272477 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -745,6 +745,9 @@ LLVMRustOptimize( if (InstrProfileOutput) { Options.InstrProfileOutput = InstrProfileOutput; } + // cargo run tests in multhreading mode by default + // so use atomics for coverage counters + Options.Atomic = true; MPM.addPass(InstrProfiling(Options, false)); } ); @@ -1460,63 +1463,6 @@ LLVMRustGetBitcodeSliceFromObjectData(const char *data, return BitcodeOrError->getBufferStart(); } -// Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See -// the comment in `back/lto.rs` for why this exists. -extern "C" void -LLVMRustThinLTOGetDICompileUnit(LLVMModuleRef Mod, - DICompileUnit **A, - DICompileUnit **B) { - Module *M = unwrap(Mod); - DICompileUnit **Cur = A; - DICompileUnit **Next = B; - for (DICompileUnit *CU : M->debug_compile_units()) { - *Cur = CU; - Cur = Next; - Next = nullptr; - if (Cur == nullptr) - break; - } -} - -// Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See -// the comment in `back/lto.rs` for why this exists. -extern "C" void -LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) { - Module *M = unwrap(Mod); - - // If the original source module didn't have a `DICompileUnit` then try to - // merge all the existing compile units. If there aren't actually any though - // then there's not much for us to do so return. - if (Unit == nullptr) { - for (DICompileUnit *CU : M->debug_compile_units()) { - Unit = CU; - break; - } - if (Unit == nullptr) - return; - } - - // Use LLVM's built-in `DebugInfoFinder` to find a bunch of debuginfo and - // process it recursively. Note that we used to specifically iterate over - // instructions to ensure we feed everything into it, but `processModule` - // started doing this the same way in LLVM 7 (commit d769eb36ab2b8). - DebugInfoFinder Finder; - Finder.processModule(*M); - - // After we've found all our debuginfo, rewrite all subprograms to point to - // the same `DICompileUnit`. - for (auto &F : Finder.subprograms()) { - F->replaceUnit(Unit); - } - - // Erase any other references to other `DICompileUnit` instances, the verifier - // will later ensure that we don't actually have any other stale references to - // worry about. - auto *MD = M->getNamedMetadata("llvm.dbg.cu"); - MD->clearOperands(); - MD->addOperand(Unit); -} - // Computes the LTO cache key for the provided 'ModId' in the given 'Data', // storing the result in 'KeyOut'. // Currently, this cache key is a SHA-1 hash of anything that could affect diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs index a8b25ff66d7..d0d41c614d6 100644 --- a/compiler/rustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -253,7 +253,7 @@ fn add_query_desc_cached_impl( quote! { #[allow(unused_variables, unused_braces, rustc::pass_by_value)] #[inline] - pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::ty::query::query_keys::#name<'tcx>) -> bool { + pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::query::queries::#name::Key<'tcx>) -> bool { #expr } } @@ -262,7 +262,7 @@ fn add_query_desc_cached_impl( // we're taking `key` by reference, but some rustc types usually prefer being passed by value #[allow(rustc::pass_by_value)] #[inline] - pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::ty::query::query_keys::#name<'tcx>) -> bool { + pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::query::queries::#name::Key<'tcx>) -> bool { false } } @@ -273,7 +273,7 @@ fn add_query_desc_cached_impl( let desc = quote! { #[allow(unused_variables)] - pub fn #name<'tcx>(tcx: TyCtxt<'tcx>, key: crate::ty::query::query_keys::#name<'tcx>) -> String { + pub fn #name<'tcx>(tcx: TyCtxt<'tcx>, key: crate::query::queries::#name::Key<'tcx>) -> String { let (#tcx, #key) = (tcx, key); ::rustc_middle::ty::print::with_no_trimmed_paths!( format!(#desc) diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs index e6e7d25773e..98ea9dc7501 100644 --- a/compiler/rustc_metadata/src/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -943,7 +943,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> { lint::builtin::UNUSED_CRATE_DEPENDENCIES, span, ast::CRATE_NODE_ID, - &format!( + format!( "external crate `{}` unused in `{}`: remove the dependency or add `use {} as _;`", name, self.tcx.crate_name(LOCAL_CRATE), diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs index c6af8d63289..6ec691f73b7 100644 --- a/compiler/rustc_metadata/src/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -220,7 +220,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owned_slice::slice_owned; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::MetadataRef; use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg}; use rustc_fs_util::try_canonicalize; use rustc_session::config::{self, CrateType}; @@ -246,6 +245,7 @@ pub(crate) struct CrateLocator<'a> { only_needs_metadata: bool, sysroot: &'a Path, metadata_loader: &'a dyn MetadataLoader, + cfg_version: &'static str, // Immutable per-search configuration. crate_name: Symbol, @@ -323,6 +323,7 @@ impl<'a> CrateLocator<'a> { only_needs_metadata, sysroot: &sess.sysroot, metadata_loader, + cfg_version: sess.cfg_version, crate_name, exact_paths: if hash.is_none() { sess.opts @@ -655,7 +656,7 @@ impl<'a> CrateLocator<'a> { } fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> { - let rustc_version = rustc_version(); + let rustc_version = rustc_version(self.cfg_version); let found_version = metadata.get_rustc_version(); if found_version != rustc_version { info!("Rejecting via version: expected {} got {}", rustc_version, found_version); @@ -782,7 +783,7 @@ fn get_metadata_section<'p>( if !filename.exists() { return Err(MetadataError::NotPresent(filename)); } - let raw_bytes: MetadataRef = match flavor { + let raw_bytes = match flavor { CrateFlavor::Rlib => { loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)? } @@ -843,7 +844,7 @@ fn get_metadata_section<'p>( slice_owned(mmap, Deref::deref) } }; - let blob = MetadataBlob::new(raw_bytes); + let blob = MetadataBlob(raw_bytes); if blob.is_compatible() { Ok(blob) } else { @@ -1097,7 +1098,7 @@ impl CrateError { crate_name, add_info, found_crates, - rustc_version: rustc_version(), + rustc_version: rustc_version(sess.cfg_version), }); } else if !locator.crate_rejections.via_invalid.is_empty() { let mut crate_rejections = Vec::new(); diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index a310cbb8029..834e2453ee0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -7,6 +7,7 @@ use crate::rmeta::*; use rustc_ast as ast; use rustc_data_structures::captures::Captures; use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::owned_slice::OwnedSlice; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc, OnceCell}; use rustc_data_structures::unhash::UnhashMap; @@ -18,6 +19,7 @@ use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_index::{Idx, IndexVec}; use rustc_middle::metadata::ModChild; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState}; use rustc_middle::ty::codec::TyDecoder; @@ -50,7 +52,7 @@ mod cstore_impl; /// A `MetadataBlob` internally is just a reference counted pointer to /// the actual data, so cloning it is cheap. #[derive(Clone)] -pub(crate) struct MetadataBlob(Lrc<MetadataRef>); +pub(crate) struct MetadataBlob(pub(crate) OwnedSlice); impl std::ops::Deref for MetadataBlob { type Target = [u8]; @@ -660,10 +662,6 @@ impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyTable<I, T> implement_ty_decoder!(DecodeContext<'a, 'tcx>); impl MetadataBlob { - pub(crate) fn new(metadata_ref: MetadataRef) -> MetadataBlob { - MetadataBlob(Lrc::new(metadata_ref)) - } - pub(crate) fn is_compatible(&self) -> bool { self.blob().starts_with(METADATA_HEADER) } @@ -856,7 +854,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { ty::EarlyBinder(&*output) } - fn get_variant(self, kind: &DefKind, index: DefIndex, parent_did: DefId) -> ty::VariantDef { + fn get_variant( + self, + kind: DefKind, + index: DefIndex, + parent_did: DefId, + ) -> (VariantIdx, ty::VariantDef) { let adt_kind = match kind { DefKind::Variant => ty::AdtKind::Enum, DefKind::Struct => ty::AdtKind::Struct, @@ -870,22 +873,25 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { if adt_kind == ty::AdtKind::Enum { Some(self.local_def_id(index)) } else { None }; let ctor = data.ctor.map(|(kind, index)| (kind, self.local_def_id(index))); - ty::VariantDef::new( - self.item_name(index), - variant_did, - ctor, - data.discr, - self.get_associated_item_or_field_def_ids(index) - .map(|did| ty::FieldDef { - did, - name: self.item_name(did.index), - vis: self.get_visibility(did.index), - }) - .collect(), - adt_kind, - parent_did, - false, - data.is_non_exhaustive, + ( + data.idx, + ty::VariantDef::new( + self.item_name(index), + variant_did, + ctor, + data.discr, + self.get_associated_item_or_field_def_ids(index) + .map(|did| ty::FieldDef { + did, + name: self.item_name(did.index), + vis: self.get_visibility(did.index), + }) + .collect(), + adt_kind, + parent_did, + false, + data.is_non_exhaustive, + ), ) } @@ -901,7 +907,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }; let repr = self.root.tables.repr_options.get(self, item_id).unwrap().decode(self); - let variants = if let ty::AdtKind::Enum = adt_kind { + let mut variants: Vec<_> = if let ty::AdtKind::Enum = adt_kind { self.root .tables .module_children_non_reexports @@ -912,15 +918,22 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { let kind = self.def_kind(index); match kind { DefKind::Ctor(..) => None, - _ => Some(self.get_variant(&kind, index, did)), + _ => Some(self.get_variant(kind, index, did)), } }) .collect() } else { - std::iter::once(self.get_variant(&kind, item_id, did)).collect() + std::iter::once(self.get_variant(kind, item_id, did)).collect() }; - tcx.mk_adt_def(did, adt_kind, variants, repr) + variants.sort_by_key(|(idx, _)| *idx); + + tcx.mk_adt_def( + did, + adt_kind, + variants.into_iter().map(|(_, variant)| variant).collect(), + repr, + ) } fn get_visibility(self, id: DefIndex) -> Visibility<DefId> { @@ -946,7 +959,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, sess)) } - fn get_debugger_visualizers(self) -> Vec<rustc_span::DebuggerVisualizerFile> { + fn get_debugger_visualizers(self) -> Vec<DebuggerVisualizerFile> { self.root.debugger_visualizers.decode(self).collect::<Vec<_>>() } @@ -1239,14 +1252,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } } - fn is_foreign_item(self, id: DefIndex) -> bool { - if let Some(parent) = self.def_key(id).parent { - matches!(self.def_kind(parent), DefKind::ForeignMod) - } else { - false - } - } - #[inline] fn def_key(self, index: DefIndex) -> DefKey { *self @@ -1457,28 +1462,30 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .. } = source_file_to_import; - // If this file is under $sysroot/lib/rustlib/src/ but has not been remapped - // during rust bootstrapping by `remap-debuginfo = true`, and the user - // wish to simulate that behaviour by -Z simulate-remapped-rust-src-base, + // If this file is under $sysroot/lib/rustlib/src/ + // and the user wish to simulate remapping with -Z simulate-remapped-rust-src-base, // then we change `name` to a similar state as if the rust was bootstrapped // with `remap-debuginfo = true`. // This is useful for testing so that tests about the effects of // `try_to_translate_virtual_to_real` don't have to worry about how the // compiler is bootstrapped. if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base - { - if let Some(real_dir) = &sess.opts.real_rust_source_base_dir { - for subdir in ["library", "compiler"] { - if let rustc_span::FileName::Real(ref mut old_name) = name { - if let rustc_span::RealFileName::LocalPath(local) = old_name { - if let Ok(rest) = local.strip_prefix(real_dir.join(subdir)) { - *old_name = rustc_span::RealFileName::Remapped { - local_path: None, - virtual_name: virtual_dir.join(subdir).join(rest), - }; - } - } - } + && let Some(real_dir) = &sess.opts.real_rust_source_base_dir + && let rustc_span::FileName::Real(ref mut old_name) = name { + let relative_path = match old_name { + rustc_span::RealFileName::LocalPath(local) => local.strip_prefix(real_dir).ok(), + rustc_span::RealFileName::Remapped { virtual_name, .. } => { + option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").and_then(|virtual_dir| virtual_name.strip_prefix(virtual_dir).ok()) + } + }; + debug!(?relative_path, ?virtual_dir, "simulate_remapped_rust_src_base"); + for subdir in ["library", "compiler"] { + if let Some(rest) = relative_path.and_then(|p| p.strip_prefix(subdir).ok()) { + *old_name = rustc_span::RealFileName::Remapped { + local_path: None, // FIXME: maybe we should preserve this? + virtual_name: virtual_dir.join(subdir).join(rest), + }; + break; } } } diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 4a3b783c636..364269095e0 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -14,8 +14,8 @@ use rustc_middle::metadata::ModChild; use rustc_middle::middle::exported_symbols::ExportedSymbol; use rustc_middle::middle::stability::DeprecationEntry; use rustc_middle::query::LocalCrate; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::fast_reject::SimplifiedType; -use rustc_middle::ty::query::{ExternProviders, Providers}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::cstore::CrateStore; use rustc_session::{Session, StableCrateId}; @@ -114,8 +114,8 @@ macro_rules! provide_one { ($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => $compute:block) => { fn $name<'tcx>( $tcx: TyCtxt<'tcx>, - def_id_arg: ty::query::query_keys::$name<'tcx>, - ) -> ty::query::query_provided::$name<'tcx> { + def_id_arg: rustc_middle::query::queries::$name::Key<'tcx>, + ) -> rustc_middle::query::queries::$name::ProvidedValue<'tcx> { let _prof_timer = $tcx.prof.generic_activity(concat!("metadata_decode_entry_", stringify!($name))); @@ -280,7 +280,6 @@ provide! { tcx, def_id, other, cdata, } associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) } inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) } - is_foreign_item => { cdata.is_foreign_item(def_id.index) } item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) } is_mir_available => { cdata.is_item_mir_available(def_id.index) } is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) } diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs index 05402a58701..4f280bb9d80 100644 --- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs +++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs @@ -1,6 +1,5 @@ use crate::rmeta::DecodeContext; use crate::rmeta::EncodeContext; -use rustc_data_structures::owned_slice::slice_owned; use rustc_data_structures::owned_slice::OwnedSlice; use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap}; use rustc_middle::parameterized_over_tcx; @@ -47,7 +46,7 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static> fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> { let len = d.read_usize(); let pos = d.position(); - let o = slice_owned(d.blob().clone(), |blob| &blob[pos..pos + len]); + let o = d.blob().clone().0.slice(|blob| &blob[pos..pos + len]); // Although we already have the data we need via the `OwnedSlice`, we still need // to advance the `DecodeContext`'s position so it's in a valid state after diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 29cf432b8f9..40723f41959 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -8,7 +8,7 @@ use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use rustc_data_structures::memmap::{Mmap, MmapMut}; use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher}; -use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator}; +use rustc_data_structures::sync::{join, par_for_each_in, Lrc}; use rustc_data_structures::temp_dir::MaybeTempDir; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -19,16 +19,17 @@ use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::lang_items::LangItem; use rustc_middle::hir::nested_filter; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use rustc_middle::middle::dependency_format::Linkage; use rustc_middle::middle::exported_symbols::{ metadata_symbol_name, ExportedSymbol, SymbolExportInfo, }; use rustc_middle::mir::interpret; use rustc_middle::query::LocalCrate; +use rustc_middle::query::Providers; use rustc_middle::traits::specialization_graph; use rustc_middle::ty::codec::TyEncoder; use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams}; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt}; use rustc_middle::util::common::to_readable_str; use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder}; @@ -36,9 +37,7 @@ use rustc_session::config::{CrateType, OptLevel}; use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib}; use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind}; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::{ - self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext, -}; +use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext}; use std::borrow::Borrow; use std::collections::hash_map::Entry; use std::hash::Hash; @@ -1375,9 +1374,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // Therefore, the loop over variants will encode its fields as the adt's children. } - for variant in adt_def.variants().iter() { + for (idx, variant) in adt_def.variants().iter_enumerated() { let data = VariantData { discr: variant.discr, + idx, ctor: variant.ctor.map(|(kind, def_id)| (kind, def_id.index)), is_non_exhaustive: variant.is_field_list_non_exhaustive(), }; @@ -1515,8 +1515,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if encode_opt { record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id)); - if tcx.sess.opts.unstable_opts.drop_tracking_mir && let DefKind::Generator = self.tcx.def_kind(def_id) { - record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- tcx.mir_generator_witnesses(def_id)); + if tcx.sess.opts.unstable_opts.drop_tracking_mir + && let DefKind::Generator = self.tcx.def_kind(def_id) + && let Some(witnesses) = tcx.mir_generator_witnesses(def_id) + { + record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- witnesses); } } if encode_const { @@ -1641,9 +1644,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } hir::ItemKind::OpaqueTy(ref opaque) => { self.encode_explicit_item_bounds(def_id); - self.tables - .is_type_alias_impl_trait - .set(def_id.index, matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias)); + self.tables.is_type_alias_impl_trait.set( + def_id.index, + matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }), + ); } hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => { self.tables.impl_defaultness.set_some(def_id.index, *defaultness); @@ -1850,7 +1854,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_debugger_visualizers(&mut self) -> LazyArray<DebuggerVisualizerFile> { empty_proc_macro!(self); - self.lazy_array(self.tcx.debugger_visualizers(LOCAL_CRATE).iter()) + self.lazy_array( + self.tcx + .debugger_visualizers(LOCAL_CRATE) + .iter() + // Erase the path since it may contain privacy sensitive data + // that we don't want to end up in crate metadata. + // The path is only needed for the local crate because of + // `--emit dep-info`. + .map(DebuggerVisualizerFile::path_erased), + ) } fn encode_crate_deps(&mut self) -> LazyArray<CrateDep> { @@ -2129,7 +2142,7 @@ fn prefetch_mir(tcx: TyCtxt<'_>) { return; } - par_iter(tcx.mir_keys(())).for_each(|&def_id| { + par_for_each_in(tcx.mir_keys(()), |&def_id| { let (encode_const, encode_opt) = should_encode_mir(tcx, def_id); if encode_const { @@ -2271,7 +2284,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { }; // Encode the rustc version string in a predictable location. - rustc_version().encode(&mut ecx); + rustc_version(tcx.sess.cfg_version).encode(&mut ecx); // Encode all the entries and extra information in the crate, // culminating in the `CrateRoot` which points to all of it. diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index e2f6acb186b..97e67fcf8fd 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -2,12 +2,12 @@ use crate::creader::CrateMetadataRef; use decoder::Metadata; use def_path_hash_map::DefPathHashMapRef; use rustc_data_structures::fx::FxHashMap; +use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; use table::TableBuilder; use rustc_ast as ast; use rustc_attr as attr; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::MetadataRef; use rustc_hir as hir; use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap}; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId}; @@ -20,8 +20,8 @@ use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; use rustc_middle::mir; +use rustc_middle::query::Providers; use rustc_middle::ty::fast_reject::SimplifiedType; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, ReprOptions, Ty, UnusedGenericParams}; use rustc_middle::ty::{DeducedParamAttrs, GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt}; use rustc_serialize::opaque::FileEncoder; @@ -31,6 +31,7 @@ use rustc_span::edition::Edition; use rustc_span::hygiene::{ExpnIndex, MacroKind}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::{self, ExpnData, ExpnHash, ExpnId, Span}; +use rustc_target::abi::VariantIdx; use rustc_target::spec::{PanicStrategy, TargetTriple}; use std::marker::PhantomData; @@ -48,8 +49,8 @@ mod def_path_hash_map; mod encoder; mod table; -pub(crate) fn rustc_version() -> String { - format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version")) +pub(crate) fn rustc_version(cfg_version: &'static str) -> String { + format!("rustc {}", cfg_version) } /// Metadata encoding version. @@ -245,7 +246,7 @@ pub(crate) struct CrateRoot { proc_macro_data: Option<ProcMacroData>, tables: LazyTables, - debugger_visualizers: LazyArray<rustc_span::DebuggerVisualizerFile>, + debugger_visualizers: LazyArray<DebuggerVisualizerFile>, exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>, @@ -430,6 +431,7 @@ define_tables! { #[derive(TyEncodable, TyDecodable)] struct VariantData { + idx: VariantIdx, discr: ty::VariantDiscr, /// If this is unit or tuple-variant/struct, then this is the index of the ctor id. ctor: Option<(CtorKind, DefIndex)>, diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml index a7d97bd3cf5..7c56af1da41 100644 --- a/compiler/rustc_middle/Cargo.toml +++ b/compiler/rustc_middle/Cargo.toml @@ -11,6 +11,7 @@ chalk-ir = "0.87.0" derive_more = "0.99.17" either = "1.5.0" gsgdt = "0.1.2" +field-offset = "0.3.5" measureme = "10.0.0" polonius-engine = "0.13.0" rustc_apfloat = { path = "../rustc_apfloat" } diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index c6bbf2ef0cd..64d511c261a 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -39,5 +39,7 @@ middle_strict_coherence_needs_negative_coherence = to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled .label = due to this attribute +middle_requires_lang_item = requires `{$name}` lang_item + middle_const_not_used_in_type_alias = const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs index dc4aa18640f..046186d274c 100644 --- a/compiler/rustc_middle/src/error.rs +++ b/compiler/rustc_middle/src/error.rs @@ -1,5 +1,5 @@ use rustc_macros::Diagnostic; -use rustc_span::Span; +use rustc_span::{Span, Symbol}; use crate::ty::Ty; @@ -74,6 +74,14 @@ pub(crate) struct StrictCoherenceNeedsNegativeCoherence { } #[derive(Diagnostic)] +#[diag(middle_requires_lang_item)] +pub(crate) struct RequiresLangItem { + #[primary_span] + pub span: Option<Span>, + pub name: Symbol, +} + +#[derive(Diagnostic)] #[diag(middle_const_not_used_in_type_alias)] pub(super) struct ConstNotUsedTraitAlias { pub ct: String, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 15d672c1408..3b59df778dc 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1,11 +1,12 @@ use crate::hir::{ModuleItems, Owner}; +use crate::middle::debugger_visualizer::DebuggerVisualizerFile; use crate::query::LocalCrate; use crate::ty::TyCtxt; use rustc_ast as ast; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::svh::Svh; -use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; +use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync}; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash}; @@ -150,11 +151,6 @@ impl<'hir> Map<'hir> { self.tcx.hir_module_items(module).items() } - #[inline] - pub fn par_for_each_item(self, f: impl Fn(ItemId) + Sync + Send) { - par_for_each_in(&self.tcx.hir_crate_items(()).items[..], |id| f(*id)); - } - pub fn def_key(self, def_id: LocalDefId) -> DefKey { // Accessing the DefKey is ok, since it is part of DefPathHash. self.tcx.definitions_untracked().def_key(def_id) @@ -502,7 +498,7 @@ impl<'hir> Map<'hir> { } #[inline] - pub fn par_body_owners(self, f: impl Fn(LocalDefId) + Sync + Send) { + pub fn par_body_owners(self, f: impl Fn(LocalDefId) + DynSend + DynSync) { par_for_each_in(&self.tcx.hir_crate_items(()).body_owners[..], |&def_id| f(def_id)); } @@ -640,7 +636,7 @@ impl<'hir> Map<'hir> { } #[inline] - pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + Sync + Send) { + pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + DynSend + DynSync) { let crate_items = self.tcx.hir_crate_items(()); par_for_each_in(&crate_items.submodules[..], |module| f(module.def_id)) } @@ -1170,11 +1166,26 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh { source_file_names.sort_unstable(); + // We have to take care of debugger visualizers explicitly. The HIR (and + // thus `hir_body_hash`) contains the #[debugger_visualizer] attributes but + // these attributes only store the file path to the visualizer file, not + // their content. Yet that content is exported into crate metadata, so any + // changes to it need to be reflected in the crate hash. + let debugger_visualizers: Vec<_> = tcx + .debugger_visualizers(LOCAL_CRATE) + .iter() + // We ignore the path to the visualizer file since it's not going to be + // encoded in crate metadata and we already hash the full contents of + // the file. + .map(DebuggerVisualizerFile::path_erased) + .collect(); + let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| { let mut stable_hasher = StableHasher::new(); hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher); upstream_crates.hash_stable(&mut hcx, &mut stable_hasher); source_file_names.hash_stable(&mut hcx, &mut stable_hasher); + debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher); if tcx.sess.opts.incremental_relative_spans() { let definitions = tcx.definitions_untracked(); let mut owner_spans: Vec<_> = krate diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index 7770a5e4764..ac0b2844177 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -6,10 +6,11 @@ pub mod map; pub mod nested_filter; pub mod place; -use crate::ty::query::Providers; +use crate::query::Providers; use crate::ty::{EarlyBinder, ImplSubject, TyCtxt}; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_data_structures::sync::{par_for_each_in, Send, Sync}; +use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync}; +use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::*; use rustc_query_system::ich::StableHashingContext; @@ -77,19 +78,19 @@ impl ModuleItems { self.owners().map(|id| id.def_id) } - pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) { + pub fn par_items(&self, f: impl Fn(ItemId) + DynSend + DynSync) { par_for_each_in(&self.items[..], |&id| f(id)) } - pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + Send + Sync) { + pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + DynSend + DynSync) { par_for_each_in(&self.trait_items[..], |&id| f(id)) } - pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + Send + Sync) { + pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + DynSend + DynSync) { par_for_each_in(&self.impl_items[..], |&id| f(id)) } - pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + Send + Sync) { + pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + DynSend + DynSync) { par_for_each_in(&self.foreign_items[..], |&id| f(id)) } } @@ -110,6 +111,12 @@ impl<'tcx> TyCtxt<'tcx> { None => self.type_of(def_id).map_bound(ImplSubject::Inherent), } } + + /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`). + pub fn is_foreign_item(self, def_id: impl Into<DefId>) -> bool { + self.opt_parent(def_id.into()) + .map_or(false, |parent| matches!(self.def_kind(parent), DefKind::ForeignMod)) + } } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index c4e41e00520..56171314944 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -280,7 +280,7 @@ pub struct QueryResponse<'tcx, R> { /// should get its hidden type inferred. So we bubble the opaque type /// and the type it was compared against upwards and let the query caller /// handle it. - pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>, + pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, pub value: R, } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e9172e767e0..22ee2a8c5e5 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -85,12 +85,7 @@ mod tests; mod macros; #[macro_use] -pub mod query; - -#[macro_use] pub mod arena; -#[macro_use] -pub mod dep_graph; pub(crate) mod error; pub mod hir; pub mod infer; @@ -104,6 +99,11 @@ pub mod ty; pub mod util; mod values; +#[macro_use] +pub mod query; +#[macro_use] +pub mod dep_graph; + // Allows macros to refer to this crate as `::rustc_middle` extern crate self as rustc_middle; diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs new file mode 100644 index 00000000000..a0497d805da --- /dev/null +++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs @@ -0,0 +1,38 @@ +use rustc_data_structures::sync::Lrc; +use std::path::PathBuf; + +#[derive(HashStable)] +#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] +pub enum DebuggerVisualizerType { + Natvis, + GdbPrettyPrinter, +} + +/// A single debugger visualizer file. +#[derive(HashStable)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)] +pub struct DebuggerVisualizerFile { + /// The complete debugger visualizer source. + pub src: Lrc<[u8]>, + /// Indicates which visualizer type this targets. + pub visualizer_type: DebuggerVisualizerType, + /// The file path to the visualizer file. This is used for reporting + /// visualizer files in dep-info. Before it is written to crate metadata, + /// the path is erased to `None`, so as not to emit potentially privacy + /// sensitive data. + pub path: Option<PathBuf>, +} + +impl DebuggerVisualizerFile { + pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType, path: PathBuf) -> Self { + DebuggerVisualizerFile { src, visualizer_type, path: Some(path) } + } + + pub fn path_erased(&self) -> Self { + DebuggerVisualizerFile { + src: self.src.clone(), + visualizer_type: self.visualizer_type, + path: None, + } + } +} diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs index 343ea1f00f5..9a633e04ce7 100644 --- a/compiler/rustc_middle/src/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -18,12 +18,8 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns the `DefId` for a given `LangItem`. /// If not found, fatally aborts compilation. pub fn require_lang_item(self, lang_item: LangItem, span: Option<Span>) -> DefId { - self.lang_items().require(lang_item).unwrap_or_else(|err| { - if let Some(span) = span { - self.sess.span_fatal(span, err.to_string()) - } else { - self.sess.fatal(err.to_string()) - } + self.lang_items().get(lang_item).unwrap_or_else(|| { + self.sess.emit_fatal(crate::error::RequiresLangItem { span, name: lang_item.name() }); }) } diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs index 12aef66bcf9..bd859d4d61b 100644 --- a/compiler/rustc_middle/src/middle/limits.rs +++ b/compiler/rustc_middle/src/middle/limits.rs @@ -11,7 +11,7 @@ use crate::bug; use crate::error::LimitInvalid; -use crate::ty; +use crate::query::Providers; use rustc_ast::Attribute; use rustc_session::Session; use rustc_session::{Limit, Limits}; @@ -19,7 +19,7 @@ use rustc_span::symbol::{sym, Symbol}; use std::num::IntErrorKind; -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { providers.limits = |tcx, ()| Limits { recursion_limit: get_recursion_limit(tcx.hir().krate_attrs(), tcx.sess), move_size_limit: get_limit( diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs index 9c25f3009ba..85c5af9ca13 100644 --- a/compiler/rustc_middle/src/middle/mod.rs +++ b/compiler/rustc_middle/src/middle/mod.rs @@ -1,4 +1,5 @@ pub mod codegen_fn_attrs; +pub mod debugger_visualizer; pub mod dependency_format; pub mod exported_symbols; pub mod lang_items; @@ -32,6 +33,6 @@ pub mod region; pub mod resolve_bound_vars; pub mod stability; -pub fn provide(providers: &mut crate::ty::query::Providers) { +pub fn provide(providers: &mut crate::query::Providers) { limits::provide(providers); } diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs index 967fed687b6..aeb6a1601fc 100644 --- a/compiler/rustc_middle/src/middle/privacy.rs +++ b/compiler/rustc_middle/src/middle/privacy.rs @@ -64,7 +64,7 @@ impl EffectiveVisibility { self.at_level(level).is_public() } - pub fn from_vis(vis: Visibility) -> EffectiveVisibility { + pub const fn from_vis(vis: Visibility) -> EffectiveVisibility { EffectiveVisibility { direct: vis, reexported: vis, @@ -72,6 +72,18 @@ impl EffectiveVisibility { reachable_through_impl_trait: vis, } } + + #[must_use] + pub fn min(mut self, lhs: EffectiveVisibility, tcx: TyCtxt<'_>) -> Self { + for l in Level::all_levels() { + let rhs_vis = self.at_level_mut(l); + let lhs_vis = *lhs.at_level(l); + if rhs_vis.is_at_least(lhs_vis, tcx) { + *rhs_vis = lhs_vis; + }; + } + self + } } /// Holds a map of effective visibilities for reachable HIR nodes. @@ -137,24 +149,6 @@ impl EffectiveVisibilities { }; } - pub fn set_public_at_level( - &mut self, - id: LocalDefId, - lazy_private_vis: impl FnOnce() -> Visibility, - level: Level, - ) { - let mut effective_vis = self - .effective_vis(id) - .copied() - .unwrap_or_else(|| EffectiveVisibility::from_vis(lazy_private_vis())); - for l in Level::all_levels() { - if l <= level { - *effective_vis.at_level_mut(l) = Visibility::Public; - } - } - self.map.insert(id, effective_vis); - } - pub fn check_invariants(&self, tcx: TyCtxt<'_>, early: bool) { if !cfg!(debug_assertions) { return; @@ -219,7 +213,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { pub fn update( &mut self, id: Id, - nominal_vis: Visibility, + nominal_vis: Option<Visibility>, lazy_private_vis: impl FnOnce() -> Visibility, inherited_effective_vis: EffectiveVisibility, level: Level, @@ -243,12 +237,11 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level && level != l) { - calculated_effective_vis = - if nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) { - inherited_effective_vis_at_level - } else { - nominal_vis - }; + calculated_effective_vis = if let Some(nominal_vis) = nominal_vis && !nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) { + nominal_vis + } else { + inherited_effective_vis_at_level + } } // effective visibility can't be decreased at next update call for the // same id diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs index e45284ca506..055d8e9a352 100644 --- a/compiler/rustc_middle/src/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,7 +1,8 @@ use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar}; use crate::mir::interpret::ConstValue; -use crate::ty::{layout, query::TyCtxtAt, tls, Ty, ValTree}; +use crate::query::TyCtxtAt; +use crate::ty::{layout, tls, Ty, ValTree}; use rustc_data_structures::sync::Lock; use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed}; @@ -15,15 +16,49 @@ use std::{any::Any, backtrace::Backtrace, fmt}; pub enum ErrorHandled { /// Already reported an error for this evaluation, and the compilation is /// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`. - Reported(ErrorGuaranteed), + Reported(ReportedErrorInfo), /// Don't emit an error, the evaluation failed because the MIR was generic /// and the substs didn't fully monomorphize it. TooGeneric, } impl From<ErrorGuaranteed> for ErrorHandled { - fn from(err: ErrorGuaranteed) -> ErrorHandled { - ErrorHandled::Reported(err) + #[inline] + fn from(error: ErrorGuaranteed) -> ErrorHandled { + ErrorHandled::Reported(error.into()) + } +} + +#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)] +pub struct ReportedErrorInfo { + error: ErrorGuaranteed, + is_tainted_by_errors: bool, +} + +impl ReportedErrorInfo { + #[inline] + pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo { + ReportedErrorInfo { is_tainted_by_errors: true, error } + } + + /// Returns true if evaluation failed because MIR was tainted by errors. + #[inline] + pub fn is_tainted_by_errors(self) -> bool { + self.is_tainted_by_errors + } +} + +impl From<ErrorGuaranteed> for ReportedErrorInfo { + #[inline] + fn from(error: ErrorGuaranteed) -> ReportedErrorInfo { + ReportedErrorInfo { is_tainted_by_errors: false, error } + } +} + +impl Into<ErrorGuaranteed> for ReportedErrorInfo { + #[inline] + fn into(self) -> ErrorGuaranteed { + self.error } } @@ -89,7 +124,7 @@ fn print_backtrace(backtrace: &Backtrace) { impl From<ErrorGuaranteed> for InterpErrorInfo<'_> { fn from(err: ErrorGuaranteed) -> Self { - InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err)).into() + InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err.into())).into() } } @@ -125,7 +160,7 @@ pub enum InvalidProgramInfo<'tcx> { /// Resolution can fail if we are in a too generic context. TooGeneric, /// Abort in case errors are already reported. - AlreadyReported(ErrorGuaranteed), + AlreadyReported(ReportedErrorInfo), /// An error occurred during layout computation. Layout(layout::LayoutError<'tcx>), /// An error occurred during FnAbi computation: the passed --target lacks FFI support @@ -144,7 +179,7 @@ impl fmt::Display for InvalidProgramInfo<'_> { use InvalidProgramInfo::*; match self { TooGeneric => write!(f, "encountered overly generic constant"), - AlreadyReported(ErrorGuaranteed { .. }) => { + AlreadyReported(_) => { write!( f, "an error has already been reported elsewhere (this should not usually be printed)" diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs index e5a9766c84d..3620385fab1 100644 --- a/compiler/rustc_middle/src/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -120,8 +120,8 @@ use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, - MachineStopType, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo, - UninitBytesAccess, UnsupportedOpInfo, + MachineStopType, ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch, + UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, }; pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar}; diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index ed4ee93e97d..f53dc8cb0ec 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,9 +1,10 @@ use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId}; use crate::mir; +use crate::query::{TyCtxtAt, TyCtxtEnsure}; use crate::ty::subst::InternalSubsts; use crate::ty::visit::TypeVisitableExt; -use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt}; +use crate::ty::{self, TyCtxt}; use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_session::lint; @@ -61,7 +62,7 @@ impl<'tcx> TyCtxt<'tcx> { self.const_eval_global_id(param_env, cid, span) } Ok(None) => Err(ErrorHandled::TooGeneric), - Err(error_reported) => Err(ErrorHandled::Reported(error_reported)), + Err(err) => Err(ErrorHandled::Reported(err.into())), } } @@ -110,7 +111,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } Ok(None) => Err(ErrorHandled::TooGeneric), - Err(error_reported) => Err(ErrorHandled::Reported(error_reported)), + Err(err) => Err(ErrorHandled::Reported(err.into())), } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 55991facd89..5c71910a955 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -101,7 +101,7 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> { /// pass will be named after the type, and it will consist of a main /// loop that goes over each available MIR and applies `run_pass`. pub trait MirPass<'tcx> { - fn name(&self) -> &str { + fn name(&self) -> &'static str { let name = std::any::type_name::<Self>(); if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name } } @@ -1111,6 +1111,10 @@ pub struct VarDebugInfo<'tcx> { /// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the /// argument number in the original function before it was inlined. pub argument_index: Option<u16>, + + /// The data represents `name` dereferenced `references` times, + /// and not the direct value. + pub references: u8, } /////////////////////////////////////////////////////////////////////////// @@ -1550,8 +1554,11 @@ impl<V, T> ProjectionElem<V, T> { /// Returns `true` if this is accepted inside `VarDebugInfoContents::Place`. pub fn can_use_in_debuginfo(&self) -> bool { match self { - Self::Deref | Self::Downcast(_, _) | Self::Field(_, _) => true, - Self::ConstantIndex { .. } + Self::ConstantIndex { from_end: false, .. } + | Self::Deref + | Self::Downcast(_, _) + | Self::Field(_, _) => true, + Self::ConstantIndex { from_end: true, .. } | Self::Index(_) | Self::OpaqueCast(_) | Self::Subslice { .. } => false, @@ -1639,18 +1646,7 @@ impl<'tcx> Place<'tcx> { return self; } - let mut v: Vec<PlaceElem<'tcx>>; - - let new_projections = if self.projection.is_empty() { - more_projections - } else { - v = Vec::with_capacity(self.projection.len() + more_projections.len()); - v.extend(self.projection); - v.extend(more_projections); - &v - }; - - Place { local: self.local, projection: tcx.mk_place_elems(new_projections) } + self.as_ref().project_deeper(more_projections, tcx) } } @@ -1721,6 +1717,27 @@ impl<'tcx> PlaceRef<'tcx> { (base, *proj) }) } + + /// Generates a new place by appending `more_projections` to the existing ones + /// and interning the result. + pub fn project_deeper( + self, + more_projections: &[PlaceElem<'tcx>], + tcx: TyCtxt<'tcx>, + ) -> Place<'tcx> { + let mut v: Vec<PlaceElem<'tcx>>; + + let new_projections = if self.projection.is_empty() { + more_projections + } else { + v = Vec::with_capacity(self.projection.len() + more_projections.len()); + v.extend(self.projection); + v.extend(more_projections); + &v + }; + + Place { local: self.local, projection: tcx.mk_place_elems(new_projections) } + } } impl Debug for Place<'_> { @@ -2313,7 +2330,7 @@ impl<'tcx> ConstantKind<'tcx> { if let Some(val) = c.kind().try_eval_for_mir(tcx, param_env) { match val { Ok(val) => Self::Val(val, c.ty()), - Err(_) => Self::Ty(tcx.const_error(self.ty())), + Err(guar) => Self::Ty(tcx.const_error(self.ty(), guar)), } } else { self @@ -2325,9 +2342,7 @@ impl<'tcx> ConstantKind<'tcx> { match tcx.const_eval_resolve(param_env, uneval, None) { Ok(val) => Self::Val(val, ty), Err(ErrorHandled::TooGeneric) => self, - Err(ErrorHandled::Reported(guar)) => { - Self::Ty(tcx.const_error_with_guaranteed(ty, guar)) - } + Err(ErrorHandled::Reported(guar)) => Self::Ty(tcx.const_error(ty, guar.into())), } } } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index fa8a339631e..62c3d8cf239 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -551,8 +551,13 @@ fn write_scope_tree( } let indented_debug_info = format!( - "{0:1$}debug {2} => {3:?};", - INDENT, indent, var_debug_info.name, var_debug_info.value, + "{0:1$}debug {2} => {3:&<4$}{5:?};", + INDENT, + indent, + var_debug_info.name, + "", + var_debug_info.references as usize, + var_debug_info.value, ); writeln!( diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 33b7fe0c2dc..21faf1958e9 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -749,6 +749,29 @@ pub enum TerminatorKind<'tcx> { }, } +impl TerminatorKind<'_> { + /// Returns a simple string representation of a `TerminatorKind` variant, independent of any + /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`). + pub const fn name(&self) -> &'static str { + match self { + TerminatorKind::Goto { .. } => "Goto", + TerminatorKind::SwitchInt { .. } => "SwitchInt", + TerminatorKind::Resume => "Resume", + TerminatorKind::Terminate => "Terminate", + TerminatorKind::Return => "Return", + TerminatorKind::Unreachable => "Unreachable", + TerminatorKind::Drop { .. } => "Drop", + TerminatorKind::Call { .. } => "Call", + TerminatorKind::Assert { .. } => "Assert", + TerminatorKind::Yield { .. } => "Yield", + TerminatorKind::GeneratorDrop => "GeneratorDrop", + TerminatorKind::FalseEdge { .. } => "FalseEdge", + TerminatorKind::FalseUnwind { .. } => "FalseUnwind", + TerminatorKind::InlineAsm { .. } => "InlineAsm", + } + } +} + /// Action to be taken when a stack unwind happens. #[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)] #[derive(TypeFoldable, TypeVisitable)] diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index 4b7014e3109..596dd80bf48 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -842,6 +842,7 @@ macro_rules! make_mir_visitor { source_info, value, argument_index: _, + references: _, } = var_debug_info; self.visit_source_info(source_info); @@ -880,12 +881,11 @@ macro_rules! make_mir_visitor { ) { let Constant { span, - user_ty, + user_ty: _, // no visit method for this literal, } = constant; self.visit_span($(& $mutability)? *span); - drop(user_ty); // no visit method for this match literal { ConstantKind::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location), ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)), diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs index 28a9c1eef1a..fd02a16130f 100644 --- a/compiler/rustc_middle/src/query/erase.rs +++ b/compiler/rustc_middle/src/query/erase.rs @@ -28,7 +28,7 @@ pub fn erase<T: EraseType>(src: T) -> Erase<T> { }; Erased::<<T as EraseType>::Result> { - // SAFETY: Is it safe to transmute to MaybeUninit for types with the same sizes. + // SAFETY: It is safe to transmute to MaybeUninit for types with the same sizes. data: unsafe { transmute_copy(&src) }, } } @@ -172,6 +172,10 @@ impl EraseType for ty::Binder<'_, ty::FnSig<'_>> { type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()]; } +impl EraseType for ty::Binder<'_, &'_ ty::List<Ty<'_>>> { + type Result = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()]; +} + impl<T0, T1> EraseType for (&'_ T0, &'_ T1) { type Result = [u8; size_of::<(&'static (), &'static ())>()]; } diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 9fad2816b0d..f5b42c80487 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -4,13 +4,95 @@ //! ["Queries: demand-driven compilation"](https://rustc-dev-guide.rust-lang.org/query.html). //! This chapter includes instructions for adding new queries. -use crate::ty::{self, print::describe_as_module, TyCtxt}; +#![allow(unused_parens)] + +use crate::dep_graph; +use crate::dep_graph::DepKind; +use crate::infer::canonical::{self, Canonical}; +use crate::lint::LintExpectation; +use crate::metadata::ModChild; +use crate::middle::codegen_fn_attrs::CodegenFnAttrs; +use crate::middle::debugger_visualizer::DebuggerVisualizerFile; +use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; +use crate::middle::lib_features::LibFeatures; +use crate::middle::privacy::EffectiveVisibilities; +use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg}; +use crate::middle::stability::{self, DeprecationEntry}; +use crate::mir; +use crate::mir::interpret::GlobalId; +use crate::mir::interpret::{ + ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, +}; +use crate::mir::interpret::{LitToConstError, LitToConstInput}; +use crate::mir::mono::CodegenUnit; +use crate::query::erase::{erase, restore, Erase}; +use crate::query::plumbing::{query_ensure, query_get_at, DynamicQuery}; +use crate::thir; +use crate::traits::query::{ + CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, + CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, + CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution, +}; +use crate::traits::query::{ + DropckConstraint, DropckOutlivesResult, MethodAutoderefStepsResult, NormalizationResult, + OutlivesBound, +}; +use crate::traits::specialization_graph; +use crate::traits::{self, ImplSource}; +use crate::ty::fast_reject::SimplifiedType; +use crate::ty::layout::ValidityRequirement; +use crate::ty::subst::{GenericArg, SubstsRef}; +use crate::ty::util::AlwaysRequiresDrop; +use crate::ty::GeneratorDiagnosticData; +use crate::ty::TyCtxtFeed; +use crate::ty::{ + self, print::describe_as_module, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt, + UnusedGenericParams, +}; +use rustc_arena::TypedArena; +use rustc_ast as ast; +use rustc_ast::expand::allocator::AllocatorKind; +use rustc_attr as attr; +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; +use rustc_data_structures::steal::Steal; +use rustc_data_structures::svh::Svh; +use rustc_data_structures::sync::Lrc; +use rustc_data_structures::sync::WorkerLocal; +use rustc_data_structures::unord::UnordSet; +use rustc_errors::ErrorGuaranteed; +use rustc_hir as hir; +use rustc_hir::def::{DefKind, DocLinkResMap}; +use rustc_hir::def_id::{ + CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet, +}; +use rustc_hir::lang_items::{LangItem, LanguageItems}; +use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; +use rustc_index::IndexVec; +use rustc_query_system::ich::StableHashingContext; +use rustc_query_system::query::{try_get_cached, CacheSelector, QueryCache, QueryMode, QueryState}; +use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; +use rustc_session::cstore::{CrateDepKind, CrateSource}; +use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; +use rustc_session::lint::LintExpectationId; +use rustc_session::Limits; use rustc_span::def_id::LOCAL_CRATE; +use rustc_span::symbol::Symbol; +use rustc_span::{Span, DUMMY_SP}; +use rustc_target::abi; +use rustc_target::spec::PanicStrategy; +use std::mem; +use std::ops::Deref; +use std::path::PathBuf; +use std::sync::Arc; pub mod erase; mod keys; -pub mod on_disk_cache; pub use keys::{AsLocalKey, Key, LocalCrate}; +pub mod on_disk_cache; +#[macro_use] +pub mod plumbing; +pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue}; // Each of these queries corresponds to a function pointer field in the // `Providers` struct for requesting a value of that type, and a method @@ -236,6 +318,15 @@ rustc_queries! { cache_on_disk_if { key.is_local() } } + query opaque_types_defined_by( + key: LocalDefId + ) -> &'tcx [LocalDefId] { + desc { + |tcx| "computing the opaque types defined by `{}`", + tcx.def_path_str(key.to_def_id()) + } + } + /// Returns the list of bounds that can be used for /// `SelectionCandidate::ProjectionCandidate(_)` and /// `ProjectionTyCandidate::TraitDef`. @@ -437,7 +528,7 @@ rustc_queries! { } } - query mir_generator_witnesses(key: DefId) -> &'tcx mir::GeneratorLayout<'tcx> { + query mir_generator_witnesses(key: DefId) -> &'tcx Option<mir::GeneratorLayout<'tcx>> { arena_cache desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) } cache_on_disk_if { key.is_local() } @@ -636,12 +727,6 @@ rustc_queries! { desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) } } - /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`). - query is_foreign_item(key: DefId) -> bool { - desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) } - separate_provide_extern - } - /// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator. query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> { desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) } @@ -1700,12 +1785,18 @@ rustc_queries! { desc { "looking at the source for a crate" } separate_provide_extern } + /// Returns the debugger visualizers defined for this crate. - query debugger_visualizers(_: CrateNum) -> &'tcx Vec<rustc_span::DebuggerVisualizerFile> { + /// NOTE: This query has to be marked `eval_always` because it reads data + /// directly from disk that is not tracked anywhere else. I.e. it + /// represents a genuine input to the query system. + query debugger_visualizers(_: CrateNum) -> &'tcx Vec<DebuggerVisualizerFile> { arena_cache desc { "looking up the debugger visualizers for this crate" } separate_provide_extern + eval_always } + query postorder_cnums(_: ()) -> &'tcx [CrateNum] { eval_always desc { "generating a postorder list of CrateNums" } @@ -2093,3 +2184,6 @@ rustc_queries! { desc { "check whether two const param are definitely not equal to eachother"} } } + +rustc_query_append! { define_callbacks! } +rustc_feedable_queries! { define_feedable! } diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/query/plumbing.rs index 07d47cae5ee..97edfc2fca2 100644 --- a/compiler/rustc_middle/src/ty/query.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -1,89 +1,26 @@ -#![allow(unused_parens)] - use crate::dep_graph; use crate::dep_graph::DepKind; -use crate::infer::canonical::{self, Canonical}; -use crate::lint::LintExpectation; -use crate::metadata::ModChild; -use crate::middle::codegen_fn_attrs::CodegenFnAttrs; -use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo}; -use crate::middle::lib_features::LibFeatures; -use crate::middle::privacy::EffectiveVisibilities; -use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg}; -use crate::middle::stability::{self, DeprecationEntry}; -use crate::mir; -use crate::mir::interpret::GlobalId; -use crate::mir::interpret::{ - ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult, -}; -use crate::mir::interpret::{LitToConstError, LitToConstInput}; -use crate::mir::mono::CodegenUnit; - -use crate::query::erase::{erase, restore, Erase}; use crate::query::on_disk_cache::CacheEncoder; use crate::query::on_disk_cache::EncodedDepNodeIndex; use crate::query::on_disk_cache::OnDiskCache; -use crate::query::{AsLocalKey, Key}; -use crate::thir; -use crate::traits::query::{ - CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal, - CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal, - CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution, +use crate::query::{ + DynamicQueries, ExternProviders, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates, }; -use crate::traits::query::{ - DropckConstraint, DropckOutlivesResult, MethodAutoderefStepsResult, NormalizationResult, - OutlivesBound, -}; -use crate::traits::specialization_graph; -use crate::traits::{self, ImplSource}; -use crate::ty::context::TyCtxtFeed; -use crate::ty::fast_reject::SimplifiedType; -use crate::ty::layout::ValidityRequirement; -use crate::ty::subst::{GenericArg, SubstsRef}; -use crate::ty::util::AlwaysRequiresDrop; -use crate::ty::GeneratorDiagnosticData; -use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt, UnusedGenericParams}; +use crate::ty::TyCtxt; +use field_offset::FieldOffset; use measureme::StringId; -use rustc_arena::TypedArena; -use rustc_ast as ast; -use rustc_ast::expand::allocator::AllocatorKind; -use rustc_attr as attr; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet}; -use rustc_data_structures::steal::Steal; -use rustc_data_structures::svh::Svh; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::AtomicU64; -use rustc_data_structures::sync::Lrc; -use rustc_data_structures::sync::WorkerLocal; -use rustc_data_structures::unord::UnordSet; -use rustc_errors::ErrorGuaranteed; -use rustc_hir as hir; -use rustc_hir::def::{DefKind, DocLinkResMap}; -use rustc_hir::def_id::{ - CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet, -}; +use rustc_hir::def::DefKind; +use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::hir_id::OwnerId; -use rustc_hir::lang_items::{LangItem, LanguageItems}; -use rustc_hir::{Crate, ItemLocalId, TraitCandidate}; -use rustc_index::IndexVec; -use rustc_query_system::ich::StableHashingContext; +use rustc_query_system::dep_graph::DepNodeIndex; +use rustc_query_system::dep_graph::SerializedDepNodeIndex; pub(crate) use rustc_query_system::query::QueryJobId; use rustc_query_system::query::*; -use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; -use rustc_session::cstore::{CrateDepKind, CrateSource}; -use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib}; -use rustc_session::lint::LintExpectationId; -use rustc_session::Limits; -use rustc_span::symbol::Symbol; +use rustc_query_system::HandleCycleError; use rustc_span::{Span, DUMMY_SP}; -use rustc_target::abi; -use rustc_target::spec::PanicStrategy; - -use std::marker::PhantomData; -use std::mem; use std::ops::Deref; -use std::path::PathBuf; -use std::sync::Arc; pub struct QueryKeyStringCache { pub def_id_cache: FxHashMap<DefId, StringId>, @@ -95,19 +32,34 @@ impl QueryKeyStringCache { } } -#[derive(Clone, Copy)] -pub struct QueryStruct<'tcx> { - pub try_collect_active_jobs: fn(TyCtxt<'tcx>, &mut QueryMap<DepKind>) -> Option<()>, - pub alloc_self_profile_query_strings: fn(TyCtxt<'tcx>, &mut QueryKeyStringCache), - pub encode_query_results: - Option<fn(TyCtxt<'tcx>, &mut CacheEncoder<'_, 'tcx>, &mut EncodedDepNodeIndex)>, +pub struct DynamicQuery<'tcx, C: QueryCache> { + pub name: &'static str, + pub eval_always: bool, + pub dep_kind: DepKind, + pub handle_cycle_error: HandleCycleError, + pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key, DepKind>>, + pub query_cache: FieldOffset<QueryCaches<'tcx>, C>, + pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool, + pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value, + pub compute: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value, + pub can_load_from_disk: bool, + pub try_load_from_disk: fn( + tcx: TyCtxt<'tcx>, + key: &C::Key, + prev_index: SerializedDepNodeIndex, + index: DepNodeIndex, + ) -> Option<C::Value>, + pub loadable_from_disk: + fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool, + pub hash_result: HashResult<C::Value>, + pub value_from_cycle_error: fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> C::Value, + pub format_value: fn(&C::Value) -> String, } pub struct QuerySystemFns<'tcx> { pub engine: QueryEngine, pub local_providers: Providers, pub extern_providers: ExternProviders, - pub query_structs: Vec<QueryStruct<'tcx>>, pub encode_query_results: fn( tcx: TyCtxt<'tcx>, encoder: &mut CacheEncoder<'_, 'tcx>, @@ -120,6 +72,7 @@ pub struct QuerySystem<'tcx> { pub states: QueryStates<'tcx>, pub arenas: QueryArenas<'tcx>, pub caches: QueryCaches<'tcx>, + pub dynamic_queries: DynamicQueries<'tcx>, /// This provides access to the incremental compilation on-disk cache for query results. /// Do not access this directly. It is only meant to be used by @@ -130,23 +83,6 @@ pub struct QuerySystem<'tcx> { pub fns: QuerySystemFns<'tcx>, pub jobs: AtomicU64, - - // Since we erase query value types we tell the typesystem about them with `PhantomData`. - _phantom_values: QueryPhantomValues<'tcx>, -} - -impl<'tcx> QuerySystem<'tcx> { - pub fn new(fns: QuerySystemFns<'tcx>, on_disk_cache: Option<OnDiskCache<'tcx>>) -> Self { - QuerySystem { - states: Default::default(), - arenas: Default::default(), - caches: Default::default(), - on_disk_cache, - fns, - jobs: AtomicU64::new(1), - _phantom_values: Default::default(), - } - } } #[derive(Copy, Clone)] @@ -203,7 +139,7 @@ impl<'tcx> TyCtxt<'tcx> { } #[inline] -fn query_get_at<'tcx, Cache>( +pub fn query_get_at<'tcx, Cache>( tcx: TyCtxt<'tcx>, execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>, query_cache: &Cache, @@ -221,7 +157,7 @@ where } #[inline] -fn query_ensure<'tcx, Cache>( +pub fn query_ensure<'tcx, Cache>( tcx: TyCtxt<'tcx>, execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>, query_cache: &Cache, @@ -275,8 +211,8 @@ macro_rules! separate_provide_extern_decl { ([(separate_provide_extern) $($rest:tt)*][$name:ident]) => { for<'tcx> fn( TyCtxt<'tcx>, - query_keys::$name<'tcx>, - ) -> query_provided::$name<'tcx> + queries::$name::Key<'tcx>, + ) -> queries::$name::ProvidedValue<'tcx> }; ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { separate_provide_extern_decl!([$($modifiers)*][$($args)*]) @@ -306,60 +242,37 @@ macro_rules! define_callbacks { $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { - // HACK(eddyb) this is like the `impl QueryConfig for queries::$name` - // below, but using type aliases instead of associated types, to bypass - // the limitations around normalizing under HRTB - for example, this: - // `for<'tcx> fn(...) -> <queries::$name<'tcx> as QueryConfig<TyCtxt<'tcx>>>::Value` - // doesn't currently normalize to `for<'tcx> fn(...) -> query_values::$name<'tcx>`. - // This is primarily used by the `provide!` macro in `rustc_metadata`. - #[allow(nonstandard_style, unused_lifetimes)] - pub mod query_keys { - use super::*; - - $(pub type $name<'tcx> = $($K)*;)* - } - #[allow(nonstandard_style, unused_lifetimes)] - pub mod query_keys_local { - use super::*; - - $(pub type $name<'tcx> = local_key_if_separate_extern!([$($modifiers)*] $($K)*);)* - } - #[allow(nonstandard_style, unused_lifetimes)] - pub mod query_values { - use super::*; + #[allow(unused_lifetimes)] + pub mod queries { + $(pub mod $name { + use super::super::*; - $(pub type $name<'tcx> = $V;)* - } + pub type Key<'tcx> = $($K)*; + pub type Value<'tcx> = $V; - /// This module specifies the type returned from query providers and the type used for - /// decoding. For regular queries this is the declared returned type `V`, but - /// `arena_cache` will use `<V as Deref>::Target` instead. - #[allow(nonstandard_style, unused_lifetimes)] - pub mod query_provided { - use super::*; + pub type LocalKey<'tcx> = local_key_if_separate_extern!([$($modifiers)*] $($K)*); - $( - pub type $name<'tcx> = query_if_arena!([$($modifiers)*] (<$V as Deref>::Target) ($V)); - )* - } - - /// This module has a function per query which takes a `query_provided` value and coverts - /// it to a regular `V` value by allocating it on an arena if the query has the - /// `arena_cache` modifier. This will happen when computing the query using a provider or - /// decoding a stored result. - #[allow(nonstandard_style, unused_lifetimes)] - pub mod query_provided_to_value { - use super::*; + /// This type alias specifies the type returned from query providers and the type + /// used for decoding. For regular queries this is the declared returned type `V`, + /// but `arena_cache` will use `<V as Deref>::Target` instead. + pub type ProvidedValue<'tcx> = query_if_arena!( + [$($modifiers)*] + (<$V as Deref>::Target) + ($V) + ); - $( + /// This function takes `ProvidedValue` and coverts it to an erased `Value` by + /// allocating it on an arena if the query has the `arena_cache` modifier. The + /// value is then erased and returned. This will happen when computing the query + /// using a provider or decoding a stored result. #[inline(always)] - pub fn $name<'tcx>( + pub fn provided_to_erased<'tcx>( _tcx: TyCtxt<'tcx>, - value: query_provided::$name<'tcx>, - ) -> Erase<query_values::$name<'tcx>> { + value: ProvidedValue<'tcx>, + ) -> Erase<Value<'tcx>> { erase(query_if_arena!([$($modifiers)*] { - if mem::needs_drop::<query_provided::$name<'tcx>>() { + if mem::needs_drop::<ProvidedValue<'tcx>>() { &*_tcx.query_system.arenas.$name.alloc(value) } else { &*_tcx.arena.dropless.alloc(value) @@ -368,47 +281,41 @@ macro_rules! define_callbacks { (value) )) } - )* - } - #[allow(nonstandard_style, unused_lifetimes)] - pub mod query_storage { - use super::*; - $( - pub type $name<'tcx> = <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>>>::Cache; - )* + pub type Storage<'tcx> = < + <$($K)* as keys::Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>> + >::Cache; + + // Ensure that keys grow no larger than 64 bytes + #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] + const _: () = { + if mem::size_of::<Key<'static>>() > 64 { + panic!("{}", concat!( + "the query `", + stringify!($name), + "` has a key type `", + stringify!($($K)*), + "` that is too large" + )); + } + }; + + // Ensure that values grow no larger than 64 bytes + #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] + const _: () = { + if mem::size_of::<Value<'static>>() > 64 { + panic!("{}", concat!( + "the query `", + stringify!($name), + "` has a value type `", + stringify!($V), + "` that is too large" + )); + } + }; + })* } - $( - // Ensure that keys grow no larger than 64 bytes - #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] - const _: () = { - if mem::size_of::<query_keys::$name<'static>>() > 64 { - panic!("{}", concat!( - "the query `", - stringify!($name), - "` has a key type `", - stringify!($($K)*), - "` that is too large" - )); - } - }; - - // Ensure that values grow no larger than 64 bytes - #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] - const _: () = { - if mem::size_of::<query_values::$name<'static>>() > 64 { - panic!("{}", concat!( - "the query `", - stringify!($name), - "` has a value type `", - stringify!($V), - "` that is too large" - )); - } - }; - )* - pub struct QueryArenas<'tcx> { $($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*] (WorkerLocal<TypedArena<<$V as Deref>::Target>>) @@ -428,13 +335,8 @@ macro_rules! define_callbacks { } #[derive(Default)] - pub struct QueryPhantomValues<'tcx> { - $($(#[$attr])* pub $name: PhantomData<query_values::$name<'tcx>>,)* - } - - #[derive(Default)] pub struct QueryCaches<'tcx> { - $($(#[$attr])* pub $name: query_storage::$name<'tcx>,)* + $($(#[$attr])* pub $name: queries::$name::Storage<'tcx>,)* } impl<'tcx> TyCtxtEnsure<'tcx> { @@ -490,6 +392,12 @@ macro_rules! define_callbacks { })* } + pub struct DynamicQueries<'tcx> { + $( + pub $name: DynamicQuery<'tcx, queries::$name::Storage<'tcx>>, + )* + } + #[derive(Default)] pub struct QueryStates<'tcx> { $( @@ -500,8 +408,8 @@ macro_rules! define_callbacks { pub struct Providers { $(pub $name: for<'tcx> fn( TyCtxt<'tcx>, - query_keys_local::$name<'tcx>, - ) -> query_provided::$name<'tcx>,)* + queries::$name::LocalKey<'tcx>, + ) -> queries::$name::ProvidedValue<'tcx>,)* } pub struct ExternProviders { @@ -546,7 +454,7 @@ macro_rules! define_callbacks { $(pub $name: for<'tcx> fn( TyCtxt<'tcx>, Span, - query_keys::$name<'tcx>, + queries::$name::Key<'tcx>, QueryMode, ) -> Option<Erase<$V>>,)* } @@ -570,11 +478,11 @@ macro_rules! define_feedable { $(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> { $(#[$attr])* #[inline(always)] - pub fn $name(self, value: query_provided::$name<'tcx>) { + pub fn $name(self, value: queries::$name::ProvidedValue<'tcx>) { let key = self.key().into_query_param(); let tcx = self.tcx; - let erased = query_provided_to_value::$name(tcx, value); + let erased = queries::$name::provided_to_erased(tcx, value); let value = restore::<$V>(erased); let cache = &tcx.query_system.caches.$name; @@ -586,12 +494,20 @@ macro_rules! define_feedable { let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx.with_stable_hashing_context(|mut hcx| (hasher(&mut hcx, &value), hasher(&mut hcx, &old)) ); - assert_eq!( - old_hash, value_hash, - "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}", - stringify!($name), - ) + if old_hash != value_hash { + // We have an inconsistency. This can happen if one of the two + // results is tainted by errors. In this case, delay a bug to + // ensure compilation is doomed, and keep the `old` value. + tcx.sess.delay_span_bug(DUMMY_SP, format!( + "Trying to feed an already recorded value for query {} key={key:?}:\n\ + old value: {old:?}\nnew value: {value:?}", + stringify!($name), + )); + } } else { + // The query is `no_hash`, so we have no way to perform a sanity check. + // If feeding the same value multiple times needs to be supported, + // the query should not be marked `no_hash`. bug!( "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}", stringify!($name), @@ -627,9 +543,6 @@ macro_rules! define_feedable { // Queries marked with `fatal_cycle` do not need the latter implementation, // as they will raise an fatal error on query cycles instead. -rustc_query_append! { define_callbacks! } -rustc_feedable_queries! { define_feedable! } - mod sealed { use super::{DefId, LocalDefId, OwnerId}; diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 449c453555e..5b0b40cbfd9 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -281,9 +281,6 @@ pub enum ObligationCauseCode<'tcx> { /// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`. ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>), - /// Obligation incurred due to an object cast. - ObjectCastObligation(/* Concrete type */ Ty<'tcx>, /* Object type */ Ty<'tcx>), - /// Obligation incurred due to a coercion. Coercion { source: Ty<'tcx>, @@ -704,9 +701,9 @@ impl<'tcx, N> ImplSource<'tcx, N> { } pub fn borrow_nested_obligations(&self) -> &[N] { - match &self { - ImplSource::UserDefined(i) => &i.nested[..], - ImplSource::Param(n, _) => &n, + match self { + ImplSource::UserDefined(i) => &i.nested, + ImplSource::Param(n, _) => n, ImplSource::Builtin(i) => &i.nested, ImplSource::AutoImpl(d) => &d.nested, ImplSource::Closure(c) => &c.nested, @@ -720,6 +717,23 @@ impl<'tcx, N> ImplSource<'tcx, N> { } } + pub fn borrow_nested_obligations_mut(&mut self) -> &mut [N] { + match self { + ImplSource::UserDefined(i) => &mut i.nested, + ImplSource::Param(n, _) => n, + ImplSource::Builtin(i) => &mut i.nested, + ImplSource::AutoImpl(d) => &mut d.nested, + ImplSource::Closure(c) => &mut c.nested, + ImplSource::Generator(c) => &mut c.nested, + ImplSource::Future(c) => &mut c.nested, + ImplSource::Object(d) => &mut d.nested, + ImplSource::FnPointer(d) => &mut d.nested, + ImplSource::TraitAlias(d) => &mut d.nested, + ImplSource::TraitUpcasting(d) => &mut d.nested, + ImplSource::ConstDestruct(i) => &mut i.nested, + } + } + pub fn map<M, F>(self, f: F) -> ImplSource<'tcx, M> where F: FnMut(N) -> M, diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs index 6b7b910a59b..1511c906d1e 100644 --- a/compiler/rustc_middle/src/traits/solve.rs +++ b/compiler/rustc_middle/src/traits/solve.rs @@ -124,7 +124,7 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> { pub struct ExternalConstraintsData<'tcx> { // FIXME: implement this. pub region_constraints: QueryRegionConstraints<'tcx>, - pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>, + pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>, } // FIXME: Having to clone `region_constraints` for folding feels bad and diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs index 468c2c818b2..cbc68fde9d9 100644 --- a/compiler/rustc_middle/src/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -83,7 +83,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(self.tcx().ty_error(guar)), - _ => relate::super_relate_tys(self, a, b), + _ => relate::structurally_relate_tys(self, a, b), } } @@ -109,7 +109,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> { _ => {} } - relate::super_relate_consts(self, a, b) + relate::structurally_relate_consts(self, a, b) } fn binders<T>( diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs index 972c417cbba..a39631da936 100644 --- a/compiler/rustc_middle/src/ty/abstract_const.rs +++ b/compiler/rustc_middle/src/ty/abstract_const.rs @@ -53,7 +53,7 @@ impl<'tcx> TyCtxt<'tcx> { fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> { let ct = match c.kind() { ty::ConstKind::Unevaluated(uv) => match self.tcx.thir_abstract_const(uv.def) { - Err(e) => self.tcx.const_error_with_guaranteed(c.ty(), e), + Err(e) => self.tcx.const_error(c.ty(), e), Ok(Some(bac)) => { let substs = self.tcx.erase_regions(uv.substs); let bac = bac.subst(self.tcx, substs); diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index ad9891a5dca..7c5c030c276 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -111,12 +111,30 @@ impl Ord for AdtDefData { } } -/// There should be only one AdtDef for each `did`, therefore -/// it is fine to implement `PartialEq` only based on `did`. impl PartialEq for AdtDefData { #[inline] fn eq(&self, other: &Self) -> bool { - self.did == other.did + // There should be only one `AdtDefData` for each `def_id`, therefore + // it is fine to implement `PartialEq` only based on `def_id`. + // + // Below, we exhaustively destructure `self` and `other` so that if the + // definition of `AdtDefData` changes, a compile-error will be produced, + // reminding us to revisit this assumption. + + let Self { did: self_def_id, variants: _, flags: _, repr: _ } = self; + let Self { did: other_def_id, variants: _, flags: _, repr: _ } = other; + + let res = self_def_id == other_def_id; + + // Double check that implicit assumption detailed above. + if cfg!(debug_assertions) && res { + let deep = self.flags == other.flags + && self.repr == other.repr + && self.variants == other.variants; + assert!(deep, "AdtDefData for the same def-id has differing data"); + } + + res } } diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index f29bf92b0ed..be7b2b7ec67 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -5,6 +5,7 @@ use crate::{mir, ty}; use std::fmt::Write; +use crate::query::Providers; use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{self as hir, LangItem}; @@ -457,6 +458,6 @@ impl BorrowKind { } } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { closure_typeinfo, ..*providers } +pub fn provide(providers: &mut Providers) { + *providers = Providers { closure_typeinfo, ..*providers } } diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index e7107c28bf4..1a4bd14815f 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -6,7 +6,6 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::LocalDefId; use rustc_macros::HashStable; -use std::fmt; mod int; mod kind; @@ -21,15 +20,6 @@ pub use valtree::*; #[rustc_pass_by_value] pub struct Const<'tcx>(pub(super) Interned<'tcx, ConstData<'tcx>>); -impl<'tcx> fmt::Debug for Const<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // This reflects what `Const` looked liked before `Interned` was - // introduced. We print it like this to avoid having to update expected - // output in a lot of tests. - write!(f, "Const {{ ty: {:?}, kind: {:?} }}", self.ty(), self.kind()) - } -} - /// Typed constant value. #[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)] pub struct ConstData<'tcx> { @@ -142,9 +132,7 @@ impl<'tcx> Const<'tcx> { ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)), param_ty, )), - Some(rbv::ResolvedArg::Error(guar)) => { - Some(tcx.const_error_with_guaranteed(param_ty, guar)) - } + Some(rbv::ResolvedArg::Error(guar)) => Some(tcx.const_error(param_ty, guar)), arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id), } } @@ -228,7 +216,7 @@ impl<'tcx> Const<'tcx> { if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) { match val { Ok(val) => tcx.mk_const(val, self.ty()), - Err(guar) => tcx.const_error_with_guaranteed(self.ty(), guar), + Err(guar) => tcx.const_error(self.ty(), guar), } } else { // Either the constant isn't evaluatable or ValTree creation failed. diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs index 1ac2cd13982..1dd4f8a2437 100644 --- a/compiler/rustc_middle/src/ty/consts/kind.rs +++ b/compiler/rustc_middle/src/ty/consts/kind.rs @@ -42,7 +42,7 @@ impl<'tcx> UnevaluatedConst<'tcx> { } /// Represents a constant in Rust. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)] #[derive(Hash, HashStable, TypeFoldable, TypeVisitable)] #[derive(derive_more::From)] pub enum ConstKind<'tcx> { @@ -128,7 +128,7 @@ impl<'tcx> ConstKind<'tcx> { } /// An inference variable for a const, for use in const generics. -#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] +#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)] pub enum InferConst<'tcx> { /// Infer the value of the const. Var(ty::ConstVid<'tcx>), @@ -245,7 +245,7 @@ impl<'tcx> ConstKind<'tcx> { // can leak through `val` into the const we return. Ok(val) => Some(Ok(EvalResult::ValTree(val?))), Err(ErrorHandled::TooGeneric) => None, - Err(ErrorHandled::Reported(e)) => Some(Err(e)), + Err(ErrorHandled::Reported(e)) => Some(Err(e.into())), } } EvalMode::Mir => { @@ -256,7 +256,7 @@ impl<'tcx> ConstKind<'tcx> { // can leak through `val` into the const we return. Ok(val) => Some(Ok(EvalResult::ConstVal(val))), Err(ErrorHandled::TooGeneric) => None, - Err(ErrorHandled::Reported(e)) => Some(Err(e)), + Err(ErrorHandled::Reported(e)) => Some(Err(e.into())), } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 8aea2d8aedf..bbea3e1412b 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -14,15 +14,14 @@ use crate::middle::resolve_bound_vars; use crate::middle::stability; use crate::mir::interpret::{self, Allocation, ConstAllocation}; use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted}; -use crate::query::on_disk_cache::OnDiskCache; +use crate::query::plumbing::QuerySystem; use crate::query::LocalCrate; +use crate::query::Providers; +use crate::query::{IntoQueryParam, TyCtxtAt}; use crate::thir::Thir; use crate::traits; use crate::traits::solve; use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData}; -use crate::ty::query::QuerySystem; -use crate::ty::query::QuerySystemFns; -use crate::ty::query::{self, TyCtxtAt}; use crate::ty::{ self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid, GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy, @@ -81,8 +80,6 @@ use std::iter; use std::mem; use std::ops::{Bound, Deref}; -use super::query::IntoQueryParam; - const TINY_CONST_EVAL_LIMIT: Limit = Limit(20); #[allow(rustc::usage_of_ty_tykind)] @@ -496,7 +493,7 @@ pub struct GlobalCtxt<'tcx> { /// /// FIXME(Centril): consider `dyn LintStoreMarker` once /// we can upcast to `Any` for some additional type safety. - pub lint_store: Lrc<dyn Any + sync::Sync + sync::Send>, + pub lint_store: Lrc<dyn Any + sync::DynSync + sync::DynSend>, pub dep_graph: DepGraph, @@ -513,7 +510,7 @@ pub struct GlobalCtxt<'tcx> { untracked: Untracked, - pub query_system: query::QuerySystem<'tcx>, + pub query_system: QuerySystem<'tcx>, pub(crate) query_kinds: &'tcx [DepKindStruct<'tcx>], // Internal caches for metadata decoding. No need to track deps on this. @@ -648,14 +645,13 @@ impl<'tcx> TyCtxt<'tcx> { /// reference to the context, to allow formatting values that need it. pub fn create_global_ctxt( s: &'tcx Session, - lint_store: Lrc<dyn Any + sync::Send + sync::Sync>, + lint_store: Lrc<dyn Any + sync::DynSend + sync::DynSync>, arena: &'tcx WorkerLocal<Arena<'tcx>>, hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>, untracked: Untracked, dep_graph: DepGraph, - on_disk_cache: Option<OnDiskCache<'tcx>>, query_kinds: &'tcx [DepKindStruct<'tcx>], - query_system_fns: QuerySystemFns<'tcx>, + query_system: QuerySystem<'tcx>, ) -> GlobalCtxt<'tcx> { let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| { s.emit_fatal(err); @@ -677,7 +673,7 @@ impl<'tcx> TyCtxt<'tcx> { lifetimes: common_lifetimes, consts: common_consts, untracked, - query_system: QuerySystem::new(query_system_fns, on_disk_cache), + query_system, query_kinds, ty_rcache: Default::default(), pred_rcache: Default::default(), @@ -704,7 +700,11 @@ impl<'tcx> TyCtxt<'tcx> { /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to /// ensure it gets used. #[track_caller] - pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty<'tcx> { + pub fn ty_error_with_message<S: Into<MultiSpan>>( + self, + span: S, + msg: impl Into<DiagnosticMessage>, + ) -> Ty<'tcx> { let reported = self.sess.delay_span_bug(span, msg); self.mk_ty_from_kind(Error(reported)) } @@ -735,17 +735,13 @@ impl<'tcx> TyCtxt<'tcx> { /// Like [TyCtxt::ty_error] but for constants, with current `ErrorGuaranteed` #[track_caller] - pub fn const_error_with_guaranteed( - self, - ty: Ty<'tcx>, - reported: ErrorGuaranteed, - ) -> Const<'tcx> { + pub fn const_error(self, ty: Ty<'tcx>, reported: ErrorGuaranteed) -> Const<'tcx> { self.mk_const(ty::ConstKind::Error(reported), ty) } /// Like [TyCtxt::ty_error] but for constants. #[track_caller] - pub fn const_error(self, ty: Ty<'tcx>) -> Const<'tcx> { + pub fn const_error_misc(self, ty: Ty<'tcx>) -> Const<'tcx> { self.const_error_with_message( ty, DUMMY_SP, @@ -2441,7 +2437,7 @@ impl<'tcx> TyCtxtAt<'tcx> { /// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to /// ensure it gets used. #[track_caller] - pub fn ty_error_with_message(self, msg: &str) -> Ty<'tcx> { + pub fn ty_error_with_message(self, msg: impl Into<DiagnosticMessage>) -> Ty<'tcx> { self.tcx.ty_error_with_message(self.span, msg) } } @@ -2461,7 +2457,7 @@ pub struct DeducedParamAttrs { pub read_only: bool, } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { providers.maybe_unused_trait_imports = |tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports; providers.names_imported_by_glob_use = |tcx, id| { diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs index fb0d909307e..5c1c419811e 100644 --- a/compiler/rustc_middle/src/ty/context/tls.rs +++ b/compiler/rustc_middle/src/ty/context/tls.rs @@ -1,7 +1,7 @@ use super::{GlobalCtxt, TyCtxt}; use crate::dep_graph::TaskDepsRef; -use crate::ty::query; +use crate::query::plumbing::QueryJobId; use rustc_data_structures::sync::{self, Lock}; use rustc_errors::Diagnostic; #[cfg(not(parallel_compiler))] @@ -22,7 +22,7 @@ pub struct ImplicitCtxt<'a, 'tcx> { /// The current query job, if any. This is updated by `JobOwner::start` in /// `ty::query::plumbing` when executing a query. - pub query: Option<query::QueryJobId>, + pub query: Option<QueryJobId>, /// Where to store diagnostics for the current query job, if any. /// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query. @@ -94,8 +94,8 @@ where f(None) } else { // We could get an `ImplicitCtxt` pointer from another thread. - // Ensure that `ImplicitCtxt` is `Sync`. - sync::assert_sync::<ImplicitCtxt<'_, '_>>(); + // Ensure that `ImplicitCtxt` is `DynSync`. + sync::assert_dyn_sync::<ImplicitCtxt<'_, '_>>(); unsafe { f(Some(downcast(context))) } } diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index ad930d1e6b6..7895993ccff 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -1,8 +1,9 @@ +use crate::query::Providers; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::ty::{self, Ty, TyCtxt, TypeFlags, TypeVisitableExt}; -pub(super) fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { erase_regions_ty, ..*providers }; +pub(super) fn provide(providers: &mut Providers) { + *providers = Providers { erase_regions_ty, ..*providers }; } fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs index baef4ffeda7..99174bae3f6 100644 --- a/compiler/rustc_middle/src/ty/generics.rs +++ b/compiler/rustc_middle/src/ty/generics.rs @@ -103,7 +103,7 @@ impl GenericParamDef { ty::GenericParamDefKind::Lifetime => tcx.mk_re_error_misc().into(), ty::GenericParamDefKind::Type { .. } => tcx.ty_error_misc().into(), ty::GenericParamDefKind::Const { .. } => { - tcx.const_error(tcx.type_of(self.def_id).subst(tcx, preceding_substs)).into() + tcx.const_error_misc(tcx.type_of(self.def_id).subst(tcx, preceding_substs)).into() } } } diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs index 9e672004cf9..4223502848e 100644 --- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -43,6 +43,7 @@ //! This code should only compile in modules where the uninhabitedness of `Foo` //! is visible. +use crate::query::Providers; use crate::ty::context::TyCtxt; use crate::ty::{self, DefId, Ty, VariantDef, Visibility}; @@ -52,9 +53,8 @@ pub mod inhabited_predicate; pub use inhabited_predicate::InhabitedPredicate; -pub(crate) fn provide(providers: &mut ty::query::Providers) { - *providers = - ty::query::Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers }; +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers }; } /// Returns an `InhabitedPredicate` that is generic over type parameters and diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 47cf48f46cf..b5a743cfe34 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -1,5 +1,6 @@ use crate::fluent_generated as fluent; use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use crate::query::TyCtxtAt; use crate::ty::normalize_erasing_regions::NormalizationError; use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitableExt}; use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic}; @@ -268,7 +269,7 @@ pub struct LayoutCx<'tcx, C> { impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> { type TargetDataLayoutRef = &'tcx TargetDataLayout; - fn delay_bug(&self, txt: &str) { + fn delay_bug(&self, txt: String) { self.tcx.sess.delay_span_bug(DUMMY_SP, txt); } @@ -543,20 +544,20 @@ impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> { } } -impl<'tcx> HasDataLayout for ty::query::TyCtxtAt<'tcx> { +impl<'tcx> HasDataLayout for TyCtxtAt<'tcx> { #[inline] fn data_layout(&self) -> &TargetDataLayout { &self.data_layout } } -impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> { +impl<'tcx> HasTargetSpec for TyCtxtAt<'tcx> { fn target_spec(&self) -> &Target { &self.sess.target } } -impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> { +impl<'tcx> HasTyCtxt<'tcx> for TyCtxtAt<'tcx> { #[inline] fn tcx(&self) -> TyCtxt<'tcx> { **self @@ -683,7 +684,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> { } } -impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> { +impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> { type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>; #[inline] diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs index 30f036e471c..71911a5a618 100644 --- a/compiler/rustc_middle/src/ty/list.rs +++ b/compiler/rustc_middle/src/ty/list.rs @@ -199,6 +199,12 @@ impl<'a, T: Copy> IntoIterator for &'a List<T> { unsafe impl<T: Sync> Sync for List<T> {} +// We need this since `List` uses extern type `OpaqueListContents`. +#[cfg(parallel_compiler)] +use rustc_data_structures::sync::DynSync; +#[cfg(parallel_compiler)] +unsafe impl<T: DynSync> DynSync for List<T> {} + // Safety: // Layouts of `Equivalent<T>` and `List<T>` are the same, modulo opaque tail, // thus aligns of `Equivalent<T>` and `List<T>` must be the same. diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index f882f54d628..ecb191676c2 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -21,6 +21,7 @@ use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason}; use crate::metadata::ModChild; use crate::middle::privacy::EffectiveVisibilities; use crate::mir::{Body, GeneratorLayout}; +use crate::query::Providers; use crate::traits::{self, Reveal}; use crate::ty; use crate::ty::fast_reject::SimplifiedType; @@ -121,7 +122,6 @@ pub mod inhabitedness; pub mod layout; pub mod normalize_erasing_regions; pub mod print; -pub mod query; pub mod relate; pub mod subst; pub mod trait_def; @@ -1070,6 +1070,24 @@ impl ParamTerm { } } +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub enum TermVid<'tcx> { + Ty(ty::TyVid), + Const(ty::ConstVid<'tcx>), +} + +impl From<ty::TyVid> for TermVid<'_> { + fn from(value: ty::TyVid) -> Self { + TermVid::Ty(value) + } +} + +impl<'tcx> From<ty::ConstVid<'tcx>> for TermVid<'tcx> { + fn from(value: ty::ConstVid<'tcx>) -> Self { + TermVid::Const(value) + } +} + /// This kind of predicate has no *direct* correspondent in the /// syntax, but it roughly corresponds to the syntactic forms: /// @@ -1864,7 +1882,20 @@ impl PartialEq for VariantDef { let Self { def_id: lhs_def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = &self; let Self { def_id: rhs_def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = other; - lhs_def_id == rhs_def_id + + let res = lhs_def_id == rhs_def_id; + + // Double check that implicit assumption detailed above. + if cfg!(debug_assertions) && res { + let deep = self.ctor == other.ctor + && self.name == other.name + && self.discr == other.discr + && self.fields == other.fields + && self.flags == other.flags; + assert!(deep, "VariantDef for the same def-id has differing data"); + } + + res } } @@ -1919,7 +1950,15 @@ impl PartialEq for FieldDef { let Self { did: rhs_did, name: _, vis: _ } = other; - lhs_did == rhs_did + let res = lhs_did == rhs_did; + + // Double check that implicit assumption detailed above. + if cfg!(debug_assertions) && res { + let deep = self.name == other.name && self.vis == other.vis; + assert!(deep, "FieldDef for the same def-id has differing data"); + } + + res } } @@ -2476,6 +2515,18 @@ impl<'tcx> TyCtxt<'tcx> { } } + /// Returns the `DefId` of the item within which the `impl Trait` is declared. + /// For type-alias-impl-trait this is the `type` alias. + /// For impl-trait-in-assoc-type this is the assoc type. + /// For return-position-impl-trait this is the function. + pub fn impl_trait_parent(self, mut def_id: LocalDefId) -> LocalDefId { + // Find the surrounding item (type alias or assoc type) + while let DefKind::OpaqueTy = self.def_kind(def_id) { + def_id = self.local_parent(def_id); + } + def_id + } + pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool { if self.def_kind(def_id) != DefKind::AssocFn { return false; @@ -2520,7 +2571,7 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId> hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => { Some(parent) } - hir::OpaqueTyOrigin::TyAlias => None, + hir::OpaqueTyOrigin::TyAlias { .. } => None, }; } } @@ -2578,7 +2629,7 @@ pub fn ast_uint_ty(uty: UintTy) -> ast::UintTy { } } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { closure::provide(providers); context::provide(providers); erase_regions::provide(providers); @@ -2587,7 +2638,7 @@ pub fn provide(providers: &mut ty::query::Providers) { print::provide(providers); super::util::bug::provide(providers); super::middle::provide(providers); - *providers = ty::query::Providers { + *providers = Providers { trait_impls_of: trait_def::trait_impls_of_provider, incoherent_impls: trait_def::incoherent_impls_provider, const_param_default: consts::const_param_default, diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs index 9332b0430ff..a0c8d299f48 100644 --- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs +++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs @@ -32,7 +32,7 @@ impl<'tcx> TyCtxt<'tcx> { /// /// This should only be used outside of type inference. For example, /// it assumes that normalization will succeed. - #[tracing::instrument(level = "debug", skip(self, param_env))] + #[tracing::instrument(level = "debug", skip(self, param_env), ret)] pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T where T: TypeFoldable<TyCtxt<'tcx>>, diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs index 72710b78c93..1b336b7bfc6 100644 --- a/compiler/rustc_middle/src/ty/opaque_types.rs +++ b/compiler/rustc_middle/src/ty/opaque_types.rs @@ -207,14 +207,16 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> { Some(GenericArgKind::Const(c1)) => c1, Some(u) => panic!("const mapped to unexpected kind: {:?}", u), None => { - if !self.ignore_errors { - self.tcx.sess.emit_err(ConstNotUsedTraitAlias { + let guar = self + .tcx + .sess + .create_err(ConstNotUsedTraitAlias { ct: ct.to_string(), span: self.span, - }); - } + }) + .emit_unless(self.ignore_errors); - self.interner().const_error(ct.ty()) + self.interner().const_error(ct.ty(), guar) } } } diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs index 810c388ebbe..a2e77d9cdfe 100644 --- a/compiler/rustc_middle/src/ty/parameterized.rs +++ b/compiler/rustc_middle/src/ty/parameterized.rs @@ -56,6 +56,7 @@ trivially_parameterized_over_tcx! { std::string::String, crate::metadata::ModChild, crate::middle::codegen_fn_attrs::CodegenFnAttrs, + crate::middle::debugger_visualizer::DebuggerVisualizerFile, crate::middle::exported_symbols::SymbolExportInfo, crate::middle::resolve_bound_vars::ObjectLifetimeDefault, crate::mir::ConstQualifs, @@ -91,7 +92,6 @@ trivially_parameterized_over_tcx! { rustc_session::cstore::ForeignModule, rustc_session::cstore::LinkagePreference, rustc_session::cstore::NativeLib, - rustc_span::DebuggerVisualizerFile, rustc_span::ExpnData, rustc_span::ExpnHash, rustc_span::ExpnId, diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 926172ff828..4491d78648f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1,5 +1,6 @@ use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar}; -use crate::ty::query::IntoQueryParam; +use crate::query::IntoQueryParam; +use crate::query::Providers; use crate::ty::{ self, ConstInt, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, @@ -702,7 +703,7 @@ pub trait PrettyPrinter<'tcx>: ty::Error(_) => p!("[type error]"), ty::Param(ref param_ty) => p!(print(param_ty)), ty::Bound(debruijn, bound_ty) => match bound_ty.kind { - ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?, + ty::BoundTyKind::Anon => debug_bound_var(&mut self, debruijn, bound_ty.var)?, ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() { true if debruijn == ty::INNERMOST => p!(write("^{}", s)), true => p!(write("^{}_{}", debruijn.index(), s)), @@ -740,7 +741,7 @@ pub trait PrettyPrinter<'tcx>: } ty::Placeholder(placeholder) => match placeholder.bound.kind { ty::BoundTyKind::Anon => { - self.pretty_print_placeholder_var(placeholder.universe, placeholder.bound.var)? + debug_placeholder_var(&mut self, placeholder.universe, placeholder.bound.var)?; } ty::BoundTyKind::Param(_, name) => p!(write("{}", name)), }, @@ -1163,30 +1164,6 @@ pub trait PrettyPrinter<'tcx>: traits.entry(trait_ref).or_default().extend(proj_ty); } - fn pretty_print_bound_var( - &mut self, - debruijn: ty::DebruijnIndex, - var: ty::BoundVar, - ) -> Result<(), Self::Error> { - if debruijn == ty::INNERMOST { - write!(self, "^{}", var.index()) - } else { - write!(self, "^{}_{}", debruijn.index(), var.index()) - } - } - - fn pretty_print_placeholder_var( - &mut self, - ui: ty::UniverseIndex, - var: ty::BoundVar, - ) -> Result<(), Self::Error> { - if ui == ty::UniverseIndex::ROOT { - write!(self, "!{}", var.index()) - } else { - write!(self, "!{}_{}", ui.index(), var.index()) - } - } - fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> { None } @@ -1320,7 +1297,7 @@ pub trait PrettyPrinter<'tcx>: define_scoped_cx!(self); if self.should_print_verbose() { - p!(write("Const({:?}: {:?})", ct.kind(), ct.ty())); + p!(write("{:?}", ct)); return Ok(self); } @@ -1379,9 +1356,11 @@ pub trait PrettyPrinter<'tcx>: } ty::ConstKind::Bound(debruijn, bound_var) => { - self.pretty_print_bound_var(debruijn, bound_var)? + debug_bound_var(&mut self, debruijn, bound_var)? } - ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)), + ty::ConstKind::Placeholder(placeholder) => { + debug_placeholder_var(&mut self, placeholder.universe, placeholder.bound)?; + }, // FIXME(generic_const_exprs): // write out some legible representation of an abstract const? ty::ConstKind::Expr(_) => p!("[const expr]"), @@ -3054,8 +3033,8 @@ fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> { map } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { trimmed_def_paths, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { trimmed_def_paths, ..*providers }; } #[derive(Default)] @@ -3066,3 +3045,27 @@ pub struct OpaqueFnEntry<'tcx> { fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>, return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>, } + +pub fn debug_bound_var<T: std::fmt::Write>( + fmt: &mut T, + debruijn: ty::DebruijnIndex, + var: ty::BoundVar, +) -> Result<(), std::fmt::Error> { + if debruijn == ty::INNERMOST { + write!(fmt, "^{}", var.index()) + } else { + write!(fmt, "^{}_{}", debruijn.index(), var.index()) + } +} + +pub fn debug_placeholder_var<T: std::fmt::Write>( + fmt: &mut T, + universe: ty::UniverseIndex, + bound: ty::BoundVar, +) -> Result<(), std::fmt::Error> { + if universe == ty::UniverseIndex::ROOT { + write!(fmt, "!{}", bound.index()) + } else { + write!(fmt, "!{}_{}", universe.index(), bound.index()) + } +} diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index da43475941e..3bbe6a23b66 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -388,24 +388,24 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> { } } -/// The main "type relation" routine. Note that this does not handle -/// inference artifacts, so you should filter those out before calling -/// it. -pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( +/// Relates `a` and `b` structurally, calling the relation for all nested values. +/// Any semantic equality, e.g. of projections, and inference variables have to be +/// handled by the caller. +pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, a: Ty<'tcx>, b: Ty<'tcx>, ) -> RelateResult<'tcx, Ty<'tcx>> { let tcx = relation.tcx(); - debug!("super_relate_tys: a={:?} b={:?}", a, b); + debug!("structurally_relate_tys: a={:?} b={:?}", a, b); match (a.kind(), b.kind()) { (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { // The caller should handle these cases! - bug!("var types encountered in super_relate_tys") + bug!("var types encountered in structurally_relate_tys") } (ty::Bound(..), _) | (_, ty::Bound(..)) => { - bug!("bound types encountered in super_relate_tys") + bug!("bound types encountered in structurally_relate_tys") } (&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(tcx.ty_error(guar)), @@ -575,15 +575,18 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>( } } -/// The main "const relation" routine. Note that this does not handle -/// inference artifacts, so you should filter those out before calling -/// it. -pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( +/// Relates `a` and `b` structurally, calling the relation for all nested values. +/// Any semantic equality, e.g. of unevaluated consts, and inference variables have +/// to be handled by the caller. +/// +/// FIXME: This is not totally structual, which probably should be fixed. +/// See the HACKs below. +pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, mut a: ty::Const<'tcx>, mut b: ty::Const<'tcx>, ) -> RelateResult<'tcx, ty::Const<'tcx>> { - debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); + debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b); let tcx = relation.tcx(); // HACK(const_generics): We still need to eagerly evaluate consts when @@ -602,7 +605,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( b = tcx.expand_abstract_consts(b); } - debug!("{}.super_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b); + debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b); // Currently, the values that can be unified are primitive types, // and those that derive both `PartialEq` and `Eq`, corresponding @@ -610,7 +613,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>( let is_match = match (a.kind(), b.kind()) { (ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => { // The caller should handle these cases! - bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b) + bug!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b) } (ty::ConstKind::Error(_), _) => return Ok(a), diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 29a3bc8bb97..16cb6c91046 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -192,6 +192,44 @@ impl<'tcx> fmt::Debug for AliasTy<'tcx> { } } +impl<'tcx> fmt::Debug for ty::InferConst<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + InferConst::Var(var) => write!(f, "{var:?}"), + InferConst::Fresh(var) => write!(f, "Fresh({var:?})"), + } + } +} + +impl<'tcx> fmt::Debug for ty::Const<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // This reflects what `Const` looked liked before `Interned` was + // introduced. We print it like this to avoid having to update expected + // output in a lot of tests. + write!(f, "Const {{ ty: {:?}, kind: {:?} }}", self.ty(), self.kind()) + } +} + +impl<'tcx> fmt::Debug for ty::ConstKind<'tcx> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use ty::ConstKind::*; + match self { + Param(param) => write!(f, "{param:?}"), + Infer(var) => write!(f, "{var:?}"), + Bound(debruijn, var) => ty::print::debug_bound_var(f, *debruijn, *var), + Placeholder(placeholder) => { + ty::print::debug_placeholder_var(f, placeholder.universe, placeholder.bound) + } + Unevaluated(uv) => { + f.debug_tuple("Unevaluated").field(&uv.substs).field(&uv.def).finish() + } + Value(valtree) => write!(f, "{valtree:?}"), + Error(_) => write!(f, "[const error]"), + Expr(expr) => write!(f, "{expr:?}"), + } + } +} + /////////////////////////////////////////////////////////////////////////// // Atomic structs // @@ -204,6 +242,7 @@ CloneLiftImpls! { (), bool, usize, + u8, u16, u32, u64, diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 488d83b5f67..e6d51c4ec97 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1265,7 +1265,7 @@ impl<'tcx> AliasTy<'tcx> { /// Extracts the underlying trait reference and own substs from this projection. /// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`, - /// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs + /// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own substs pub fn trait_ref_and_own_substs( self, tcx: TyCtxt<'tcx>, @@ -1708,7 +1708,9 @@ impl<'tcx> Region<'tcx> { ty::ReErased => { flags = flags | TypeFlags::HAS_RE_ERASED; } - ty::ReError(_) => {} + ty::ReError(_) => { + flags = flags | TypeFlags::HAS_FREE_REGIONS; + } } debug!("type_flags({:?}) = {:?}", self, flags); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index bcb51db9bcf..eb903ebfd99 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -2,6 +2,7 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags; use crate::mir; +use crate::query::Providers; use crate::ty::layout::IntegerExt; use crate::ty::{ self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, @@ -34,9 +35,14 @@ pub struct Discr<'tcx> { /// Used as an input to [`TyCtxt::uses_unique_generic_params`]. #[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum IgnoreRegions { - Yes, +pub enum CheckRegions { No, + /// Only permit early bound regions. This is useful for Adts which + /// can never have late bound regions. + OnlyEarlyBound, + /// Permit both late bound and early bound regions. Use this for functions, + /// which frequently have late bound regions. + Bound, } #[derive(Copy, Clone, Debug)] @@ -468,21 +474,28 @@ impl<'tcx> TyCtxt<'tcx> { pub fn uses_unique_generic_params( self, substs: SubstsRef<'tcx>, - ignore_regions: IgnoreRegions, + ignore_regions: CheckRegions, ) -> Result<(), NotUniqueParam<'tcx>> { let mut seen = GrowableBitSet::default(); + let mut seen_late = FxHashSet::default(); for arg in substs { match arg.unpack() { - GenericArgKind::Lifetime(lt) => { - if ignore_regions == IgnoreRegions::No { - let ty::ReEarlyBound(p) = lt.kind() else { - return Err(NotUniqueParam::NotParam(lt.into())) - }; + GenericArgKind::Lifetime(lt) => match (ignore_regions, lt.kind()) { + (CheckRegions::Bound, ty::ReLateBound(di, reg)) => { + if !seen_late.insert((di, reg)) { + return Err(NotUniqueParam::DuplicateParam(lt.into())); + } + } + (CheckRegions::OnlyEarlyBound | CheckRegions::Bound, ty::ReEarlyBound(p)) => { if !seen.insert(p.index) { return Err(NotUniqueParam::DuplicateParam(lt.into())); } } - } + (CheckRegions::OnlyEarlyBound | CheckRegions::Bound, _) => { + return Err(NotUniqueParam::NotParam(lt.into())); + } + (CheckRegions::No, _) => {} + }, GenericArgKind::Type(t) => match t.kind() { ty::Param(p) => { if !seen.insert(p.index) { @@ -655,10 +668,10 @@ impl<'tcx> TyCtxt<'tcx> { self, def_id: DefId, ) -> impl Iterator<Item = ty::EarlyBinder<Ty<'tcx>>> { - let generator_layout = &self.mir_generator_witnesses(def_id); + let generator_layout = self.mir_generator_witnesses(def_id); generator_layout - .field_tys - .iter() + .as_ref() + .map_or_else(|| [].iter(), |l| l.field_tys.iter()) .filter(|decl| !decl.ignore_for_traits) .map(|decl| ty::EarlyBinder(decl.ty)) } @@ -1472,8 +1485,8 @@ pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic) } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { +pub fn provide(providers: &mut Providers) { + *providers = Providers { reveal_opaque_types_in_bounds, is_doc_hidden, is_doc_notable_trait, diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs index 3dfd0824f98..43ee0343f5a 100644 --- a/compiler/rustc_middle/src/util/bug.rs +++ b/compiler/rustc_middle/src/util/bug.rs @@ -48,6 +48,6 @@ pub fn trigger_delay_span_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) { ); } -pub fn provide(providers: &mut crate::ty::query::Providers) { - *providers = crate::ty::query::Providers { trigger_delay_span_bug, ..*providers }; +pub fn provide(providers: &mut crate::query::Providers) { + *providers = crate::query::Providers { trigger_delay_span_bug, ..*providers }; } diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs index 931fe1b2433..b74422708ce 100644 --- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs @@ -154,6 +154,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> { Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset)))) }, @call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)), + @call("mir_copy_for_deref", args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)), ExprKind::Borrow { borrow_kind, arg } => Ok( Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?) ), 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 59549435233..4d99ab4b0ec 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -52,7 +52,7 @@ pub fn as_constant_inner<'tcx>( match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) { Ok(c) => c, Err(LitToConstError::Reported(guar)) => { - ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar)) + ConstantKind::Ty(tcx.const_error(ty, guar)) } Err(LitToConstError::TypeError) => { bug!("encountered type error in `lit_to_mir_constant`") diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs index 4926ff85de3..6df06df5c60 100644 --- a/compiler/rustc_mir_build/src/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -2241,6 +2241,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info: debug_source_info, + references: 0, value: VarDebugInfoContents::Place(for_arm_body.into()), argument_index: None, }); @@ -2260,6 +2261,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info: debug_source_info, + references: 0, value: VarDebugInfoContents::Place(ref_for_guard.into()), argument_index: None, }); diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 4536ecf17b8..dbdb5b4a9a1 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -380,18 +380,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } - /// Compare two `&T` values using `<T as std::compare::PartialEq>::eq` + /// Compare two values using `<T as std::compare::PartialEq>::eq`. + /// If the values are already references, just call it directly, otherwise + /// take a reference to the values first and then call it. fn non_scalar_compare( &mut self, block: BasicBlock, make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>, source_info: SourceInfo, value: ConstantKind<'tcx>, - place: Place<'tcx>, + mut val: Place<'tcx>, mut ty: Ty<'tcx>, ) { let mut expect = self.literal_operand(source_info.span, value); - let mut val = Operand::Copy(place); // If we're using `b"..."` as a pattern, we need to insert an // unsizing coercion, as the byte string has the type `&[u8; N]`. @@ -421,9 +422,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { block, source_info, temp, - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), val, ty), + Rvalue::Cast( + CastKind::Pointer(PointerCast::Unsize), + Operand::Copy(val), + ty, + ), ); - val = Operand::Move(temp); + val = temp; } if opt_ref_test_ty.is_some() { let slice = self.temp(ty, source_info.span); @@ -438,12 +443,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - let ty::Ref(_, deref_ty, _) = *ty.kind() else { - bug!("non_scalar_compare called on non-reference type: {}", ty); - }; + match *ty.kind() { + ty::Ref(_, deref_ty, _) => ty = deref_ty, + _ => { + // non_scalar_compare called on non-reference type + let temp = self.temp(ty, source_info.span); + self.cfg.push_assign(block, source_info, temp, Rvalue::Use(expect)); + let ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, ty); + let ref_temp = self.temp(ref_ty, source_info.span); + + self.cfg.push_assign( + block, + source_info, + ref_temp, + Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, temp), + ); + expect = Operand::Move(ref_temp); + + let ref_temp = self.temp(ref_ty, source_info.span); + self.cfg.push_assign( + block, + source_info, + ref_temp, + Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, val), + ); + val = ref_temp; + } + } let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span)); - let method = trait_method(self.tcx, eq_def_id, sym::eq, [deref_ty, deref_ty]); + let method = trait_method(self.tcx, eq_def_id, sym::eq, [ty, ty]); let bool_ty = self.tcx.types.bool; let eq_result = self.temp(bool_ty, source_info.span); @@ -463,7 +492,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { literal: method, })), - args: vec![val, expect], + args: vec![Operand::Copy(val), expect], destination: eq_result, target: Some(eq_block), unwind: UnwindAction::Continue, diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 20d381eddb1..4e3e98b56e7 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -798,6 +798,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { }; self.var_debug_info.push(VarDebugInfo { name, + references: 0, source_info: SourceInfo::outermost(captured_place.var_ident.span), value: VarDebugInfoContents::Place(use_place), argument_index: None, @@ -828,6 +829,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.var_debug_info.push(VarDebugInfo { name, source_info, + references: 0, value: VarDebugInfoContents::Place(arg_local.into()), argument_index: Some(argument_index as u16 + 1), }); diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs index 56c87c402fe..b01b6fbf222 100644 --- a/compiler/rustc_mir_build/src/build/scope.rs +++ b/compiler/rustc_mir_build/src/build/scope.rs @@ -644,24 +644,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } }; - if let Some(destination) = destination { - if let Some(value) = value { + match (destination, value) { + (Some(destination), Some(value)) => { debug!("stmt_expr Break val block_context.push(SubExpr)"); self.block_context.push(BlockFrame::SubExpr); unpack!(block = self.expr_into_dest(destination, block, value)); self.block_context.pop(); - } else { + } + (Some(destination), None) => { self.cfg.push_assign_unit(block, source_info, destination, self.tcx) } - } else { - assert!(value.is_none(), "`return` and `break` should have a destination"); - if self.tcx.sess.instrument_coverage() { + (None, Some(_)) => { + panic!("`return`, `become` and `break` with value and must have a destination") + } + (None, None) if self.tcx.sess.instrument_coverage() => { // Unlike `break` and `return`, which push an `Assign` statement to MIR, from which // a Coverage code region can be generated, `continue` needs no `Assign`; but // without one, the `InstrumentCoverage` MIR pass cannot generate a code region for // `continue`. Coverage will be missing unless we add a dummy `Assign` to MIR. self.add_dummy_assignment(span, block, source_info); } + (None, None) => {} } let region_scope = self.scopes.breakable_scopes[break_index].region_scope; @@ -671,12 +674,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } else { self.scopes.breakable_scopes[break_index].continue_drops.as_mut().unwrap() }; - let mut drop_idx = ROOT_NODE; - for scope in &self.scopes.scopes[scope_index + 1..] { - for drop in &scope.drops { - drop_idx = drops.add_drop(*drop, drop_idx); - } - } + + let drop_idx = self.scopes.scopes[scope_index + 1..] + .iter() + .flat_map(|scope| &scope.drops) + .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx)); + drops.add_entry(block, drop_idx); // `build_drop_trees` doesn't have access to our source_info, so we diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 2765a107cf0..c964e62c9d0 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -22,7 +22,7 @@ mod errors; mod lints; pub mod thir; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index f46eb5a0ce1..c8648224ac1 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -130,6 +130,7 @@ impl<'tcx> Cx<'tcx> { ExprKind::Pointer { cast: PointerCast::Unsize, source: self.thir.exprs.push(expr) } } Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.thir.exprs.push(expr) }, + Adjust::NeverToAny if adjustment.target.is_never() => return expr, Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) }, Adjust::Deref(None) => { adjust_span(&mut expr); 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 c73f8284ca5..b243f1dc8d0 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 @@ -62,21 +62,13 @@ struct ConstToPat<'tcx> { treat_byte_string_as_slice: bool, } -mod fallback_to_const_ref { - #[derive(Debug)] - /// This error type signals that we encountered a non-struct-eq situation behind a reference. - /// We bubble this up in order to get back to the reference destructuring and make that emit - /// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq` - /// on such patterns (since that function takes a reference) and not have to jump through any - /// hoops to get a reference to the value. - pub(super) struct FallbackToConstRef(()); - - pub(super) fn fallback_to_const_ref(c2p: &super::ConstToPat<'_>) -> FallbackToConstRef { - assert!(c2p.behind_reference.get()); - FallbackToConstRef(()) - } -} -use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef}; +/// This error type signals that we encountered a non-struct-eq situation. +/// We bubble this up in order to get back to the reference destructuring and make that emit +/// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq` +/// on such patterns (since that function takes a reference) and not have to jump through any +/// hoops to get a reference to the value. +#[derive(Debug)] +struct FallbackToConstRef; impl<'tcx> ConstToPat<'tcx> { fn new( @@ -236,13 +228,13 @@ impl<'tcx> ConstToPat<'tcx> { let kind = match cv.ty().kind() { ty::Float(_) => { - tcx.emit_spanned_lint( - lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - id, - span, - FloatPattern, - ); - PatKind::Constant { value: cv } + tcx.emit_spanned_lint( + lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + id, + span, + FloatPattern, + ); + return Err(FallbackToConstRef); } ty::Adt(adt_def, _) if adt_def.is_union() => { // Matching on union fields is unsafe, we can't hide it in constants @@ -289,7 +281,7 @@ impl<'tcx> ConstToPat<'tcx> { // Since we are behind a reference, we can just bubble the error up so we get a // constant at reference type, making it easy to let the fallback call // `PartialEq::eq` on it. - return Err(fallback_to_const_ref(self)); + return Err(FallbackToConstRef); } ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty()) => { debug!( @@ -393,11 +385,11 @@ impl<'tcx> ConstToPat<'tcx> { self.behind_reference.set(old); val } - // Backwards compatibility hack: support references to non-structural types. - // We'll lower - // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a - // reference. This makes the rest of the matching logic simpler as it doesn't have - // to figure out how to get a reference again. + // Backwards compatibility hack: support references to non-structural types, + // but hard error if we aren't behind a double reference. We could just use + // the fallback code path below, but that would allow *more* of this fishy + // code to compile, as then it only goes through the future incompat lint + // instead of a hard error. ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => { if self.behind_reference.get() { if !self.saw_const_match_error.get() @@ -411,7 +403,7 @@ impl<'tcx> ConstToPat<'tcx> { IndirectStructuralMatch { non_sm_ty: *pointee_ty }, ); } - PatKind::Constant { value: cv } + return Err(FallbackToConstRef); } else { if !self.saw_const_match_error.get() { self.saw_const_match_error.set(true); @@ -435,16 +427,9 @@ impl<'tcx> ConstToPat<'tcx> { PatKind::Wild } else { let old = self.behind_reference.replace(true); - // In case there are structural-match violations somewhere in this subpattern, - // we fall back to a const pattern. If we do not do this, we may end up with - // a !structural-match constant that is not of reference type, which makes it - // very hard to invoke `PartialEq::eq` on it as a fallback. - let val = match self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false) { - Ok(subpattern) => PatKind::Deref { subpattern }, - Err(_) => PatKind::Constant { value: cv }, - }; + let subpattern = self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false)?; self.behind_reference.set(old); - val + PatKind::Deref { subpattern } } } }, @@ -452,7 +437,7 @@ impl<'tcx> ConstToPat<'tcx> { PatKind::Constant { value: cv } } ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => { - PatKind::Constant { value: cv } + return Err(FallbackToConstRef); } // FIXME: these can have very surprising behaviour where optimization levels or other // compilation choices change the runtime behaviour of the match. @@ -469,7 +454,7 @@ impl<'tcx> ConstToPat<'tcx> { PointerPattern ); } - PatKind::Constant { value: cv } + return Err(FallbackToConstRef); } _ => { self.saw_const_match_error.set(true); 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 9af13781312..6a77146138b 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -844,8 +844,8 @@ impl<'tcx> Constructor<'tcx> { } /// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is - /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is - /// assumed to have been split from a wildcard. + /// assumed to be built from `matrix.head_ctors()` with wildcards and opaques filtered out, + /// and `self` is assumed to have been split from a wildcard. fn is_covered_by_any<'p>( &self, pcx: &PatCtxt<'_, 'p, 'tcx>, @@ -894,7 +894,7 @@ impl<'tcx> Constructor<'tcx> { /// in `to_ctors`: in some cases we only return `Missing`. #[derive(Debug)] pub(super) struct SplitWildcard<'tcx> { - /// Constructors seen in the matrix. + /// Constructors (other than wildcards and opaques) seen in the matrix. matrix_ctors: Vec<Constructor<'tcx>>, /// All the constructors for this type all_ctors: SmallVec<[Constructor<'tcx>; 1]>, @@ -1037,7 +1037,7 @@ impl<'tcx> SplitWildcard<'tcx> { // Since `all_ctors` never contains wildcards, this won't recurse further. self.all_ctors = self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect(); - self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect(); + self.matrix_ctors = ctors.filter(|c| !matches!(c, Wildcard | Opaque)).cloned().collect(); } /// Whether there are any value constructors for this type that are not present in the matrix. diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index f229b10c447..e5b63506906 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -288,6 +288,22 @@ //! //! The details are not necessary to understand this file, so we explain them in //! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function. +//! +//! # Constants in patterns +//! +//! There are two kinds of constants in patterns: +//! +//! * literals (`1`, `true`, `"foo"`) +//! * named or inline consts (`FOO`, `const { 5 + 6 }`) +//! +//! The latter are converted into other patterns with literals at the leaves. For example +//! `const_to_pat(const { [1, 2, 3] })` becomes an `Array(vec![Const(1), Const(2), Const(3)])` +//! pattern. This gets problematic when comparing the constant via `==` would behave differently +//! from matching on the constant converted to a pattern. Situations like that can occur, when +//! the user implements `PartialEq` manually, and thus could make `==` behave arbitrarily different. +//! In order to honor the `==` implementation, constants of types that implement `PartialEq` manually +//! stay as a full constant and become an `Opaque` pattern. These `Opaque` patterns do not participate +//! in exhaustiveness, specialization or overlap checking. use self::ArmType::*; use self::Usefulness::*; diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs index 2e68c794356..18895072c3b 100644 --- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs +++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs @@ -276,6 +276,7 @@ where assert_eq!(self.elaborator.param_env().reveal(), Reveal::All); let field_ty = tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, substs)); + (tcx.mk_place_field(base_place, field, field_ty), subpath) }) .collect() diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index bdb4f20da10..069514d8a3b 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -7,7 +7,7 @@ use rustc_hir::intravisit; use rustc_hir::{BlockCheckMode, ExprKind, Node}; use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE}; use rustc_session::lint::Level; diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs index c565d6f13b1..319f3a79705 100644 --- a/compiler/rustc_mir_transform/src/copy_prop.rs +++ b/compiler/rustc_mir_transform/src/copy_prop.rs @@ -162,20 +162,22 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> { } fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) { - match stmt.kind { - // When removing storage statements, we need to remove both (#107511). - StatementKind::StorageLive(l) | StatementKind::StorageDead(l) - if self.storage_to_remove.contains(l) => - { - stmt.make_nop() - } - StatementKind::Assign(box (ref place, ref mut rvalue)) - if place.as_local().is_some() => - { - // Do not replace assignments. - self.visit_rvalue(rvalue, loc) - } - _ => self.super_statement(stmt, loc), + // When removing storage statements, we need to remove both (#107511). + if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = stmt.kind + && self.storage_to_remove.contains(l) + { + stmt.make_nop(); + return + } + + self.super_statement(stmt, loc); + + // Do not leave tautological assignments around. + if let StatementKind::Assign(box (lhs, ref rhs)) = stmt.kind + && let Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)) | Rvalue::CopyForDeref(rhs) = *rhs + && lhs == rhs + { + stmt.make_nop(); } } } diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs index e554c470646..35e4c24dc46 100644 --- a/compiler/rustc_mir_transform/src/coverage/debug.rs +++ b/compiler/rustc_mir_transform/src/coverage/debug.rs @@ -118,7 +118,7 @@ use rustc_middle::mir::spanview::{self, SpanViewable}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::mir::coverage::*; -use rustc_middle::mir::{self, BasicBlock, TerminatorKind}; +use rustc_middle::mir::{self, BasicBlock}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; @@ -796,7 +796,7 @@ fn bcb_to_string_sections<'tcx>( } let non_term_blocks = bcb_data.basic_blocks[0..len - 1] .iter() - .map(|&bb| format!("{:?}: {}", bb, term_type(&mir_body[bb].terminator().kind))) + .map(|&bb| format!("{:?}: {}", bb, mir_body[bb].terminator().kind.name())) .collect::<Vec<_>>(); if non_term_blocks.len() > 0 { sections.push(non_term_blocks.join("\n")); @@ -804,28 +804,7 @@ fn bcb_to_string_sections<'tcx>( sections.push(format!( "{:?}: {}", bcb_data.basic_blocks.last().unwrap(), - term_type(&bcb_data.terminator(mir_body).kind) + bcb_data.terminator(mir_body).kind.name(), )); sections } - -/// Returns a simple string representation of a `TerminatorKind` variant, independent of any -/// values it might hold. -pub(super) fn term_type(kind: &TerminatorKind<'_>) -> &'static str { - match kind { - TerminatorKind::Goto { .. } => "Goto", - TerminatorKind::SwitchInt { .. } => "SwitchInt", - TerminatorKind::Resume => "Resume", - TerminatorKind::Terminate => "Terminate", - TerminatorKind::Return => "Return", - TerminatorKind::Unreachable => "Unreachable", - TerminatorKind::Drop { .. } => "Drop", - TerminatorKind::Call { .. } => "Call", - TerminatorKind::Assert { .. } => "Assert", - TerminatorKind::Yield { .. } => "Yield", - TerminatorKind::GeneratorDrop => "GeneratorDrop", - TerminatorKind::FalseEdge { .. } => "FalseEdge", - TerminatorKind::FalseUnwind { .. } => "FalseUnwind", - TerminatorKind::InlineAsm { .. } => "InlineAsm", - } -} diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs index bf01b45eb40..74b4b4a07c5 100644 --- a/compiler/rustc_mir_transform/src/coverage/query.rs +++ b/compiler/rustc_mir_transform/src/coverage/query.rs @@ -2,7 +2,7 @@ use super::*; use rustc_middle::mir::coverage::*; use rustc_middle::mir::{self, Body, Coverage, CoverageInfo}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::def_id::DefId; diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 287ae217087..14937912cc5 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -1,4 +1,3 @@ -use super::debug::term_type; use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB}; use itertools::Itertools; @@ -40,7 +39,7 @@ impl CoverageStatement { "{}: @{}.{}: {:?}", source_range_no_file(tcx, span), bb.index(), - term_type(&term.kind), + term.kind.name(), term.kind ) } diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index 83a335197b3..90b58933df7 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -25,7 +25,6 @@ //! to: `rustc_span::create_default_session_globals_then(|| { test_here(); })`. use super::counters; -use super::debug; use super::graph; use super::spans; @@ -188,12 +187,12 @@ fn debug_basic_blocks(mir_body: &Body<'_>) -> String { | TerminatorKind::Goto { target } | TerminatorKind::InlineAsm { destination: Some(target), .. } | TerminatorKind::Yield { resume: target, .. } => { - format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), target) + format!("{}{:?}:{} -> {:?}", sp, bb, kind.name(), target) } TerminatorKind::SwitchInt { targets, .. } => { - format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), targets) + format!("{}{:?}:{} -> {:?}", sp, bb, kind.name(), targets) } - _ => format!("{}{:?}:{}", sp, bb, debug::term_type(kind)), + _ => format!("{}{:?}:{}", sp, bb, kind.name()), } }) .collect::<Vec<_>>() @@ -215,7 +214,7 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) { " {:?} [label=\"{:?}: {}\"];\n{}", bb, bb, - debug::term_type(&data.terminator().kind), + data.terminator().kind.name(), mir_body .basic_blocks .successors(bb) @@ -244,7 +243,7 @@ fn print_coverage_graphviz( " {:?} [label=\"{:?}: {}\"];\n{}", bcb, bcb, - debug::term_type(&bcb_data.terminator(mir_body).kind), + bcb_data.terminator(mir_body).kind.name(), basic_coverage_blocks .successors(bcb) .map(|successor| { format!(" {:?} -> {:?};", bcb, successor) }) diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs index 8ee08c5be34..a133c9d4782 100644 --- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs +++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs @@ -8,7 +8,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{Body, Local, Location, Operand, Terminator, TerminatorKind, RETURN_PLACE}; +use rustc_middle::mir::{Body, Location, Operand, Place, Terminator, TerminatorKind, RETURN_PLACE}; use rustc_middle::ty::{self, DeducedParamAttrs, Ty, TyCtxt}; use rustc_session::config::OptLevel; @@ -29,31 +29,31 @@ impl DeduceReadOnly { } impl<'tcx> Visitor<'tcx> for DeduceReadOnly { - fn visit_local(&mut self, local: Local, mut context: PlaceContext, _: Location) { + fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) { // We're only interested in arguments. - if local == RETURN_PLACE || local.index() > self.mutable_args.domain_size() { + if place.local == RETURN_PLACE || place.local.index() > self.mutable_args.domain_size() { return; } - // Replace place contexts that are moves with copies. This is safe in all cases except - // function argument position, which we already handled in `visit_terminator()` by using the - // ArgumentChecker. See the comment in that method for more details. - // - // In the future, we might want to move this out into a separate pass, but for now let's - // just do it on the fly because that's faster. - if matches!(context, PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)) { - context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy); - } - - match context { - PlaceContext::MutatingUse(..) - | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => { + let mark_as_mutable = match context { + PlaceContext::MutatingUse(..) => { // This is a mutation, so mark it as such. - self.mutable_args.insert(local.index() - 1); + true + } + PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) => { + // Whether mutating though a `&raw const` is allowed is still undecided, so we + // disable any sketchy `readonly` optimizations for now. + // But we only need to do this if the pointer would point into the argument. + !place.is_indirect() } PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => { // Not mutating, so it's fine. + false } + }; + + if mark_as_mutable { + self.mutable_args.insert(place.local.index() - 1); } } diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs index 594cbd8977e..746e3d9652d 100644 --- a/compiler/rustc_mir_transform/src/dump_mir.rs +++ b/compiler/rustc_mir_transform/src/dump_mir.rs @@ -12,7 +12,7 @@ use rustc_session::config::OutputType; pub struct Marker(pub &'static str); impl<'tcx> MirPass<'tcx> for Marker { - fn name(&self) -> &str { + fn name(&self) -> &'static str { self.0 } diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index ac1de989a72..58cc161ddcc 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -1,8 +1,8 @@ use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE}; use rustc_middle::mir::*; use rustc_middle::query::LocalCrate; +use rustc_middle::query::Providers; use rustc_middle::ty::layout; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::FFI_UNWIND_CALLS; use rustc_target::spec::abi::Abi; diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index c9144729145..891e446942e 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -1397,7 +1397,7 @@ fn create_cases<'tcx>( pub(crate) fn mir_generator_witnesses<'tcx>( tcx: TyCtxt<'tcx>, def_id: LocalDefId, -) -> GeneratorLayout<'tcx> { +) -> Option<GeneratorLayout<'tcx>> { assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir); let (body, _) = tcx.mir_promoted(def_id); @@ -1410,6 +1410,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>( // Get the interior types and substs which typeck computed let movable = match *gen_ty.kind() { ty::Generator(_, _, movability) => movability == hir::Movability::Movable, + ty::Error(_) => return None, _ => span_bug!(body.span, "unexpected generator type {}", gen_ty), }; @@ -1425,7 +1426,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>( check_suspend_tys(tcx, &generator_layout, &body); - generator_layout + Some(generator_layout) } impl<'tcx> MirPass<'tcx> for StateTransform { diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs index ece20d8d3e6..6c2e22a70b9 100644 --- a/compiler/rustc_mir_transform/src/inline.rs +++ b/compiler/rustc_mir_transform/src/inline.rs @@ -7,6 +7,7 @@ use rustc_index::Idx; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; +use rustc_middle::ty::TypeVisitableExt; use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt}; use rustc_session::config::OptLevel; use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span}; @@ -167,8 +168,20 @@ impl<'tcx> Inliner<'tcx> { ) -> Result<std::ops::Range<BasicBlock>, &'static str> { let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id()); self.check_codegen_attributes(callsite, callee_attrs)?; + + let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); + let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; + let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty; + for arg in args { + if !arg.ty(&caller_body.local_decls, self.tcx).is_sized(self.tcx, self.param_env) { + // We do not allow inlining functions with unsized params. Inlining these functions + // could create unsized locals, which are unsound and being phased out. + return Err("Call has unsized argument"); + } + } + self.check_mir_is_available(caller_body, &callsite.callee)?; - let callee_body = self.tcx.instance_mir(callsite.callee.def); + let callee_body = try_instance_mir(self.tcx, callsite.callee.def)?; self.check_mir_body(callsite, callee_body, callee_attrs)?; if !self.tcx.consider_optimizing(|| { @@ -188,9 +201,6 @@ impl<'tcx> Inliner<'tcx> { // Check call signature compatibility. // Normally, this shouldn't be required, but trait normalization failure can create a // validation ICE. - let terminator = caller_body[callsite.block].terminator.as_ref().unwrap(); - let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() }; - let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty; let output_type = callee_body.return_ty(); if !util::is_subtype(self.tcx, self.param_env, output_type, destination_ty) { trace!(?output_type, ?destination_ty); @@ -1128,3 +1138,27 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> { } } } + +#[instrument(skip(tcx), level = "debug")] +fn try_instance_mir<'tcx>( + tcx: TyCtxt<'tcx>, + instance: InstanceDef<'tcx>, +) -> Result<&'tcx Body<'tcx>, &'static str> { + match instance { + ty::InstanceDef::DropGlue(_, Some(ty)) => match ty.kind() { + ty::Adt(def, substs) => { + let fields = def.all_fields(); + for field in fields { + let field_ty = field.ty(tcx, substs); + if field_ty.has_param() && field_ty.has_projections() { + return Err("cannot build drop shim for polymorphic type"); + } + } + + Ok(tcx.instance_mir(instance)) + } + _ => Ok(tcx.instance_mir(instance)), + }, + _ => Ok(tcx.instance_mir(instance)), + } +} diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs index 6bff535586a..e4dc617620e 100644 --- a/compiler/rustc_mir_transform/src/instsimplify.rs +++ b/compiler/rustc_mir_transform/src/instsimplify.rs @@ -5,7 +5,6 @@ use crate::MirPass; use rustc_hir::Mutability; use rustc_middle::mir::*; use rustc_middle::ty::layout::ValidityRequirement; -use rustc_middle::ty::util::IntTypeExt; use rustc_middle::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt}; use rustc_span::symbol::Symbol; use rustc_target::abi::FieldIdx; @@ -163,18 +162,6 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> { return; } - // Transmuting a fieldless enum to its repr is a discriminant read - if let ty::Adt(adt_def, ..) = operand_ty.kind() - && adt_def.is_enum() - && adt_def.is_payloadfree() - && let Some(place) = operand.place() - && let Some(repr_int) = adt_def.repr().int - && repr_int.to_ty(self.tcx) == *cast_ty - { - *rvalue = Rvalue::Discriminant(place); - return; - } - // Transmuting a transparent struct/union to a field's type is a projection if let ty::Adt(adt_def, substs) = operand_ty.kind() && adt_def.repr().transparent() diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 277237a5515..65864dc016f 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -34,7 +34,7 @@ use rustc_middle::mir::{ MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo, Statement, StatementKind, TerminatorKind, START_BLOCK, }; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::sym; use rustc_trait_selection::traits; diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs index e1b65823a5a..710eed3ed38 100644 --- a/compiler/rustc_mir_transform/src/pass_manager.rs +++ b/compiler/rustc_mir_transform/src/pass_manager.rs @@ -6,7 +6,7 @@ use crate::{validate, MirPass}; /// Just like `MirPass`, except it cannot mutate `Body`. pub trait MirLint<'tcx> { - fn name(&self) -> &str { + fn name(&self) -> &'static str { let name = std::any::type_name::<Self>(); if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name } } @@ -26,7 +26,7 @@ impl<'tcx, T> MirPass<'tcx> for Lint<T> where T: MirLint<'tcx>, { - fn name(&self) -> &str { + fn name(&self) -> &'static str { self.0.name() } @@ -49,7 +49,7 @@ impl<'tcx, T> MirPass<'tcx> for WithMinOptLevel<T> where T: MirPass<'tcx>, { - fn name(&self) -> &str { + fn name(&self) -> &'static str { self.1.name() } @@ -121,7 +121,7 @@ fn run_passes_inner<'tcx>( validate_body(tcx, body, format!("before pass {}", name)); } - pass.run_pass(tcx, body); + tcx.sess.time(name, || pass.run_pass(tcx, body)); if dump_enabled { dump_mir_for_pass(tcx, body, &name, true); diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs index d1bc9ee9153..bbd9f76ba5c 100644 --- a/compiler/rustc_mir_transform/src/ref_prop.rs +++ b/compiler/rustc_mir_transform/src/ref_prop.rs @@ -77,11 +77,11 @@ impl<'tcx> MirPass<'tcx> for ReferencePropagation { #[instrument(level = "trace", skip(self, tcx, body))] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { debug!(def_id = ?body.source.def_id()); - propagate_ssa(tcx, body); + while propagate_ssa(tcx, body) {} } } -fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { +fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool { let ssa = SsaLocals::new(body); let mut replacer = compute_replacement(tcx, body, &ssa); @@ -94,6 +94,8 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { if replacer.any_replacement { crate::simplify::remove_unused_definitions(body); } + + replacer.any_replacement } #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -263,6 +265,7 @@ fn compute_replacement<'tcx>( targets, storage_to_remove, allowed_replacements, + fully_replacable_locals, any_replacement: false, }; @@ -343,6 +346,7 @@ struct Replacer<'tcx> { storage_to_remove: BitSet<Local>, allowed_replacements: FxHashSet<(Local, Location)>, any_replacement: bool, + fully_replacable_locals: BitSet<Local>, } impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { @@ -350,6 +354,25 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> { self.tcx } + fn visit_var_debug_info(&mut self, debuginfo: &mut VarDebugInfo<'tcx>) { + if let VarDebugInfoContents::Place(ref mut place) = debuginfo.value + && place.projection.is_empty() + && let Value::Pointer(target, _) = self.targets[place.local] + && target.projection.iter().all(|p| p.can_use_in_debuginfo()) + { + if let Some((&PlaceElem::Deref, rest)) = target.projection.split_last() { + *place = Place::from(target.local).project_deeper(rest, self.tcx); + self.any_replacement = true; + } else if self.fully_replacable_locals.contains(place.local) + && let Some(references) = debuginfo.references.checked_add(1) + { + debuginfo.references = references; + *place = target; + self.any_replacement = true; + } + } + } + fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) { if place.projection.first() != Some(&PlaceElem::Deref) { return; diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs index 19d07fab0b9..7c47d8814db 100644 --- a/compiler/rustc_mir_transform/src/shim.rs +++ b/compiler/rustc_mir_transform/src/shim.rs @@ -2,7 +2,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_middle::mir::*; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::InternalSubsts; use rustc_middle::ty::{self, EarlyBinder, GeneratorSubsts, Ty, TyCtxt}; use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT}; diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs index 1b96df3aed5..e59219321b7 100644 --- a/compiler/rustc_mir_transform/src/simplify.rs +++ b/compiler/rustc_mir_transform/src/simplify.rs @@ -74,7 +74,7 @@ pub fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { } impl<'tcx> MirPass<'tcx> for SimplifyCfg { - fn name(&self) -> &str { + fn name(&self) -> &'static str { &self.name() } diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs index a7b45366662..2b404efccc7 100644 --- a/compiler/rustc_mir_transform/src/ssa.rs +++ b/compiler/rustc_mir_transform/src/ssa.rs @@ -101,14 +101,15 @@ impl SsaLocals { .retain(|&local| matches!(visitor.assignments[local], Set1::One(_))); debug!(?visitor.assignment_order); - let copy_classes = compute_copy_classes(&mut visitor, body); - - SsaLocals { + let mut ssa = SsaLocals { assignments: visitor.assignments, assignment_order: visitor.assignment_order, direct_uses: visitor.direct_uses, - copy_classes, - } + // This is filled by `compute_copy_classes`. + copy_classes: IndexVec::default(), + }; + compute_copy_classes(&mut ssa, body); + ssa } pub fn num_locals(&self) -> usize { @@ -261,49 +262,54 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor { } #[instrument(level = "trace", skip(ssa, body))] -fn compute_copy_classes(ssa: &mut SsaVisitor, body: &Body<'_>) -> IndexVec<Local, Local> { +fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) { + let mut direct_uses = std::mem::take(&mut ssa.direct_uses); let mut copies = IndexVec::from_fn_n(|l| l, body.local_decls.len()); - for &local in &ssa.assignment_order { - debug!(?local); - - if local == RETURN_PLACE { - // `_0` is special, we cannot rename it. - continue; - } - - // This is not SSA: mark that we don't know the value. - debug!(assignments = ?ssa.assignments[local]); - let Set1::One(LocationExtended::Plain(loc)) = ssa.assignments[local] else { continue }; - - // `loc` must point to a direct assignment to `local`. - let Either::Left(stmt) = body.stmt_at(loc) else { bug!() }; - let Some((_target, rvalue)) = stmt.kind.as_assign() else { bug!() }; - assert_eq!(_target.as_local(), Some(local)); - + for (local, rvalue, _) in ssa.assignments(body) { let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place)) = rvalue else { continue }; let Some(rhs) = place.as_local() else { continue }; - let Set1::One(_) = ssa.assignments[rhs] else { continue }; + if !ssa.is_ssa(rhs) { + continue; + } // We visit in `assignment_order`, ie. reverse post-order, so `rhs` has been // visited before `local`, and we just have to copy the representing local. - copies[local] = copies[rhs]; - ssa.direct_uses[rhs] -= 1; + let head = copies[rhs]; + + if local == RETURN_PLACE { + // `_0` is special, we cannot rename it. Instead, rename the class of `rhs` to + // `RETURN_PLACE`. This is only possible if the class head is a temporary, not an + // argument. + if body.local_kind(head) != LocalKind::Temp { + continue; + } + for h in copies.iter_mut() { + if *h == head { + *h = RETURN_PLACE; + } + } + } else { + copies[local] = head; + } + direct_uses[rhs] -= 1; } debug!(?copies); - debug!(?ssa.direct_uses); + debug!(?direct_uses); // Invariant: `copies` must point to the head of an equivalence class. #[cfg(debug_assertions)] for &head in copies.iter() { assert_eq!(copies[head], head); } + debug_assert_eq!(copies[RETURN_PLACE], RETURN_PLACE); - copies + ssa.direct_uses = direct_uses; + ssa.copy_classes = copies; } #[derive(Debug)] diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs index 55c937b305a..35b154b7b34 100644 --- a/compiler/rustc_monomorphize/src/collector.rs +++ b/compiler/rustc_monomorphize/src/collector.rs @@ -185,9 +185,9 @@ use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar}; 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::query::TyCtxtAt; use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast}; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::query::TyCtxtAt; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{ self, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 7253acf61e6..ecc50c3f664 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -12,9 +12,9 @@ extern crate rustc_middle; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir::lang_items::LangItem; +use rustc_middle::query::{Providers, TyCtxtAt}; use rustc_middle::traits; use rustc_middle::ty::adjustment::CustomCoerceUnsized; -use rustc_middle::ty::query::{Providers, TyCtxtAt}; use rustc_middle::ty::{self, Ty}; mod collector; diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs index 993e35c7fd2..eafe57a0c02 100644 --- a/compiler/rustc_monomorphize/src/partitioning/mod.rs +++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs @@ -106,8 +106,8 @@ use rustc_hir::def_id::{DefIdSet, LOCAL_CRATE}; use rustc_middle::mir; use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{CodegenUnit, Linkage}; +use rustc_middle::query::Providers; use rustc_middle::ty::print::with_no_trimmed_paths; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath}; use rustc_span::symbol::Symbol; @@ -250,13 +250,13 @@ where cgu.create_size_estimate(tcx); } - debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter()); + debug_dump(tcx, "INITIAL PARTITIONING", &initial_partitioning.codegen_units); // Merge until we have at most `max_cgu_count` codegen units. { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus"); partitioner.merge_codegen_units(cx, &mut initial_partitioning); - debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); + debug_dump(tcx, "POST MERGING", &initial_partitioning.codegen_units); } // In the next step, we use the inlining map to determine which additional @@ -272,7 +272,7 @@ where cgu.create_size_estimate(tcx); } - debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter()); + debug_dump(tcx, "POST INLINING", &post_inlining.codegen_units); // Next we try to make as many symbols "internal" as possible, so LLVM has // more freedom to optimize. @@ -322,6 +322,8 @@ where result.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str())); + debug_dump(tcx, "FINAL", &result); + result } @@ -346,33 +348,37 @@ struct PostInliningPartitioning<'tcx> { internalization_candidates: FxHashSet<MonoItem<'tcx>>, } -fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I) -where - I: Iterator<Item = &'a CodegenUnit<'tcx>>, - 'tcx: 'a, -{ +fn debug_dump<'a, 'tcx: 'a>(tcx: TyCtxt<'tcx>, label: &str, cgus: &[CodegenUnit<'tcx>]) { let dump = move || { use std::fmt::Write; + let num_cgus = cgus.len(); + let max = cgus.iter().map(|cgu| cgu.size_estimate()).max().unwrap(); + let min = cgus.iter().map(|cgu| cgu.size_estimate()).min().unwrap(); + let ratio = max as f64 / min as f64; + let s = &mut String::new(); - let _ = writeln!(s, "{label}"); + let _ = writeln!( + s, + "{label} ({num_cgus} CodegenUnits, max={max}, min={min}, max/min={ratio:.1}):" + ); for cgu in cgus { let _ = - writeln!(s, "CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate()); + writeln!(s, "CodegenUnit {} estimated size {}:", cgu.name(), cgu.size_estimate()); for (mono_item, linkage) in cgu.items() { let symbol_name = mono_item.symbol_name(tcx).name; let symbol_hash_start = symbol_name.rfind('h'); let symbol_hash = symbol_hash_start.map_or("<no hash>", |i| &symbol_name[i..]); - let _ = writeln!( + let _ = with_no_trimmed_paths!(writeln!( s, " - {} [{:?}] [{}] estimated size {}", mono_item, linkage, symbol_hash, mono_item.size_estimate(tcx) - ); + )); } let _ = writeln!(s); diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index ddc62d9c390..88a3e028527 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -11,9 +11,9 @@ use rustc_middle::mir::{ visit::{TyContext, Visitor}, Constant, ConstantKind, Local, LocalDecl, Location, }; +use rustc_middle::query::Providers; use rustc_middle::ty::{ self, - query::Providers, subst::SubstsRef, visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}, Const, Ty, TyCtxt, UnusedGenericParams, diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 1bbf833e3cd..2d0f466e236 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -478,6 +478,11 @@ parse_missing_for_in_trait_impl = missing `for` in a trait impl parse_expected_trait_in_trait_impl_found_type = expected a trait, found type +parse_extra_impl_keyword_in_trait_impl = unexpected `impl` keyword + .suggestion = remove the extra `impl` + .note = this is parsed as an `impl Trait` type, but a trait is expected at this position + + parse_non_item_in_item_list = non-item in item list .suggestion_use_const_not_let = consider using `const` instead of `let` for associated const .label_list_start = item list starts here diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index b6aeaf3d59f..84494eab855 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -1520,6 +1520,16 @@ pub(crate) struct ExpectedTraitInTraitImplFoundType { } #[derive(Diagnostic)] +#[diag(parse_extra_impl_keyword_in_trait_impl)] +pub(crate) struct ExtraImplKeywordInTraitImpl { + #[primary_span] + #[suggestion(code = "", applicability = "maybe-incorrect")] + pub extra_impl_kw: Span, + #[note] + pub impl_trait_span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_bounds_not_allowed_on_trait_aliases)] pub(crate) struct BoundsNotAllowedOnTraitAliases { #[primary_span] diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs index 51e90489002..c6e6b46e455 100644 --- a/compiler/rustc_parse/src/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -662,7 +662,7 @@ impl<'a> StringReader<'a> { &RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX, prefix_span, ast::CRATE_NODE_ID, - &format!("prefix `{prefix}` is unknown"), + format!("prefix `{prefix}` is unknown"), BuiltinLintDiagnostics::ReservedPrefix(prefix_span), ); } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 3002f23da75..bcef0f7185f 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -238,6 +238,7 @@ impl<'a> DerefMut for SnapshotParser<'a> { impl<'a> Parser<'a> { #[rustc_lint_diagnostics] + #[track_caller] pub fn struct_span_err<S: Into<MultiSpan>>( &self, sp: S, diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 887e155426f..ee712a8e1b5 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1180,6 +1180,10 @@ impl<'a> Parser<'a> { self.restore_snapshot(snapshot); let close_paren = self.prev_token.span; let span = lo.to(close_paren); + // filter shorthand fields + let fields: Vec<_> = + fields.into_iter().filter(|field| !field.is_shorthand).collect(); + if !fields.is_empty() && // `token.kind` should not be compared here. // This is because the `snapshot.token.kind` is treated as the same as diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs index e6d0f9fbc76..cd779b0b43e 100644 --- a/compiler/rustc_parse/src/parser/generics.rs +++ b/compiler/rustc_parse/src/parser/generics.rs @@ -453,6 +453,8 @@ impl<'a> Parser<'a> { // `<` (LIFETIME|IDENT) `:` - generic parameter with bounds // `<` (LIFETIME|IDENT) `=` - generic parameter with a default // `<` const - generic const parameter + // `<` IDENT `?` - RECOVERY for `impl<T ?Bound` missing a `:`, meant to + // avoid the `T?` to `Option<T>` recovery for types. // The only truly ambiguous case is // `<` IDENT `>` `::` IDENT ... // we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`) @@ -463,6 +465,9 @@ impl<'a> Parser<'a> { || self.look_ahead(start + 1, |t| t.is_lifetime() || t.is_ident()) && self.look_ahead(start + 2, |t| { matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq) + // Recovery-only branch -- this could be removed, + // since it only affects diagnostics currently. + || matches!(t.kind, token::Question) }) || self.is_keyword_ahead(start + 1, &[kw::Const])) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 840cfe90899..dc18d400f1e 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -603,10 +603,24 @@ impl<'a> Parser<'a> { let path = match ty_first.kind { // This notably includes paths passed through `ty` macro fragments (#46438). TyKind::Path(None, path) => path, - _ => { - self.sess.emit_err(errors::ExpectedTraitInTraitImplFoundType { - span: ty_first.span, - }); + other => { + if let TyKind::ImplTrait(_, bounds) = other + && let [bound] = bounds.as_slice() + { + // Suggest removing extra `impl` keyword: + // `impl<T: Default> impl Default for Wrapper<T>` + // ^^^^^ + let extra_impl_kw = ty_first.span.until(bound.span()); + self.sess + .emit_err(errors::ExtraImplKeywordInTraitImpl { + extra_impl_kw, + impl_trait_span: ty_first.span + }); + } else { + self.sess.emit_err(errors::ExpectedTraitInTraitImplFoundType { + span: ty_first.span, + }); + } err_path(ty_first.span) } }; diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 03279124177..54f9fc5d2b9 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -40,7 +40,8 @@ impl<'a> Parser<'a> { /// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of whether /// or not we have attributes - pub(crate) fn parse_stmt_without_recovery( + // Public for `cfg_eval` macro expansion. + pub fn parse_stmt_without_recovery( &mut self, capture_semi: bool, force_collect: ForceCollect, diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 982c4615aff..928fdce313d 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -186,7 +186,7 @@ fn emit_malformed_attribute( suggestions.push(code); } if should_warn(name) { - sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, &msg); + sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, msg); } else { sess.span_diagnostic .struct_span_err(span, error_msg) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 06aa2737915..41f92227e7c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -8,7 +8,6 @@ use crate::{errors, fluent_generated as fluent}; use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, IntoDiagnosticArg, MultiSpan}; -use rustc_expand::base::resolve_path; use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; @@ -19,9 +18,9 @@ use rustc_hir::{ use rustc_hir::{MethodKind, Target, Unsafety}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault; +use rustc_middle::query::Providers; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::error::{ExpectedFound, TypeError}; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::{ CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS, @@ -1916,6 +1915,10 @@ impl CheckAttrVisitor<'_> { /// Checks if the items on the `#[debugger_visualizer]` attribute are valid. fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool { + // Here we only check that the #[debugger_visualizer] attribute is attached + // to nothing other than a module. All other checks are done in the + // `debugger_visualizer` query where they need to be done for decoding + // anyway. match target { Target::Mod => {} _ => { @@ -1924,53 +1927,7 @@ impl CheckAttrVisitor<'_> { } } - let Some(hints) = attr.meta_item_list() else { - self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span }); - return false; - }; - - let hint = match hints.len() { - 1 => &hints[0], - _ => { - self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span }); - return false; - } - }; - - let Some(meta_item) = hint.meta_item() else { - self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span }); - return false; - }; - - let visualizer_path = match (meta_item.name_or_empty(), meta_item.value_str()) { - (sym::natvis_file, Some(value)) => value, - (sym::gdb_script_file, Some(value)) => value, - (_, _) => { - self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: meta_item.span }); - return false; - } - }; - - let file = - match resolve_path(&self.tcx.sess.parse_sess, visualizer_path.as_str(), attr.span) { - Ok(file) => file, - Err(mut err) => { - err.emit(); - return false; - } - }; - - match std::fs::File::open(&file) { - Ok(_) => true, - Err(error) => { - self.tcx.sess.emit_err(errors::DebugVisualizerUnreadable { - span: meta_item.span, - file: &file, - error, - }); - false - } - } + true } /// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros. diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 6742722ce52..2357b0aadef 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -12,7 +12,7 @@ use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_span::{sym, Span, Symbol}; diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index 3ae5b45d330..7812dcde44c 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -12,7 +12,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Node, PatKind, TyKind}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::Level; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{sym, Symbol}; diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index 72371b9950b..3483f7da528 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -1,60 +1,69 @@ //! Detecting usage of the `#[debugger_visualizer]` attribute. -use hir::CRATE_HIR_ID; -use rustc_data_structures::fx::FxHashSet; +use rustc_ast::Attribute; use rustc_data_structures::sync::Lrc; use rustc_expand::base::resolve_path; -use rustc_hir as hir; -use rustc_hir::HirId; -use rustc_middle::ty::TyCtxt; -use rustc_middle::{query::LocalCrate, ty::query::Providers}; -use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType}; +use rustc_middle::{ + middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType}, + query::{LocalCrate, Providers}, + ty::TyCtxt, +}; +use rustc_session::Session; +use rustc_span::sym; -use crate::errors::DebugVisualizerUnreadable; +use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable}; -fn check_for_debugger_visualizer( - tcx: TyCtxt<'_>, - hir_id: HirId, - debugger_visualizers: &mut FxHashSet<DebuggerVisualizerFile>, -) { - let attrs = tcx.hir().attrs(hir_id); - for attr in attrs { +impl DebuggerVisualizerCollector<'_> { + fn check_for_debugger_visualizer(&mut self, attr: &Attribute) { if attr.has_name(sym::debugger_visualizer) { - let Some(list) = attr.meta_item_list() else { - continue + let Some(hints) = attr.meta_item_list() else { + self.sess.emit_err(DebugVisualizerInvalid { span: attr.span }); + return; }; - let meta_item = match list.len() { - 1 => match list[0].meta_item() { - Some(meta_item) => meta_item, - _ => continue, - }, - _ => continue, + let hint = if hints.len() == 1 { + &hints[0] + } else { + self.sess.emit_err(DebugVisualizerInvalid { span: attr.span }); + return; }; - let visualizer_type = match meta_item.name_or_empty() { - sym::natvis_file => DebuggerVisualizerType::Natvis, - sym::gdb_script_file => DebuggerVisualizerType::GdbPrettyPrinter, - _ => continue, + let Some(meta_item) = hint.meta_item() else { + self.sess.emit_err(DebugVisualizerInvalid { span: attr.span }); + return; }; - let file = match meta_item.value_str() { - Some(value) => { - match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) { - Ok(file) => file, - _ => continue, + let (visualizer_type, visualizer_path) = + match (meta_item.name_or_empty(), meta_item.value_str()) { + (sym::natvis_file, Some(value)) => (DebuggerVisualizerType::Natvis, value), + (sym::gdb_script_file, Some(value)) => { + (DebuggerVisualizerType::GdbPrettyPrinter, value) } - } - None => continue, - }; + (_, _) => { + self.sess.emit_err(DebugVisualizerInvalid { span: meta_item.span }); + return; + } + }; + + let file = + match resolve_path(&self.sess.parse_sess, visualizer_path.as_str(), attr.span) { + Ok(file) => file, + Err(mut err) => { + err.emit(); + return; + } + }; match std::fs::read(&file) { Ok(contents) => { - debugger_visualizers - .insert(DebuggerVisualizerFile::new(Lrc::from(contents), visualizer_type)); + self.visualizers.push(DebuggerVisualizerFile::new( + Lrc::from(contents), + visualizer_type, + file, + )); } Err(error) => { - tcx.sess.emit_err(DebugVisualizerUnreadable { + self.sess.emit_err(DebugVisualizerUnreadable { span: meta_item.span, file: &file, error, @@ -65,29 +74,30 @@ fn check_for_debugger_visualizer( } } -/// Traverses and collects the debugger visualizers for a specific crate. -fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> { - // Initialize the collector. - let mut debugger_visualizers = FxHashSet::default(); +struct DebuggerVisualizerCollector<'a> { + sess: &'a Session, + visualizers: Vec<DebuggerVisualizerFile>, +} - // Collect debugger visualizers in this crate. - tcx.hir().for_each_module(|id| { - check_for_debugger_visualizer( - tcx, - tcx.hir().local_def_id_to_hir_id(id), - &mut debugger_visualizers, - ) - }); +impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> { + fn visit_attribute(&mut self, attr: &'ast Attribute) { + self.check_for_debugger_visualizer(attr); + rustc_ast::visit::walk_attribute(self, attr); + } +} - // Collect debugger visualizers on the crate attributes. - check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers); +/// Traverses and collects the debugger visualizers for a specific crate. +fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> { + let resolver_and_krate = tcx.resolver_for_lowering(()).borrow(); + let krate = &*resolver_and_krate.1; - // Extract out the found debugger_visualizer items. - let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>(); + let mut visitor = DebuggerVisualizerCollector { sess: tcx.sess, visualizers: Vec::new() }; + rustc_ast::visit::Visitor::visit_crate(&mut visitor, krate); - // Sort the visualizers so we always get a deterministic query result. - visualizers.sort(); - visualizers + // We are collecting visualizers in AST-order, which is deterministic, + // so we don't need to do any explicit sorting in order to get a + // deterministic query result + visitor.visualizers } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index eb6ea673c85..d8b9f4fae87 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -13,7 +13,7 @@ use rustc_ast as ast; use rustc_hir::diagnostic_items::DiagnosticItems; use rustc_hir::OwnerId; use rustc_middle::query::LocalCrate; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::{sym, Symbol}; diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs index e3e4b73efa3..ffd8f77b78b 100644 --- a/compiler/rustc_passes/src/entry.rs +++ b/compiler/rustc_passes/src/entry.rs @@ -4,7 +4,7 @@ use rustc_errors::error_code; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{ItemId, Node, CRATE_HIR_ID}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::config::{sigpipe, CrateType, EntryFnType}; use rustc_session::parse::feature_err; diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index fdd0e5dab70..476394f30cc 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -22,7 +22,7 @@ use rustc_middle::ty::TyCtxt; use rustc_session::cstore::ExternCrate; use rustc_span::{symbol::kw::Empty, Span}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; pub(crate) enum Duplicate { Plain, diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 8b7338e29aa..0da4b294648 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -22,7 +22,7 @@ extern crate tracing; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; mod check_attr; mod check_const; diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index f4da1aaec11..44174b1b89d 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -9,7 +9,7 @@ use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER}; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::LibFeatures; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs index 6758024419d..63b1578d43f 100644 --- a/compiler/rustc_passes/src/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -94,7 +94,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet}; use rustc_index::IndexVec; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt}; use rustc_session::lint; use rustc_span::symbol::{kw, sym, Symbol}; diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs index b4cf19e4a34..73cfe68e7f2 100644 --- a/compiler/rustc_passes/src/loops.rs +++ b/compiler/rustc_passes/src/loops.rs @@ -6,7 +6,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{Destination, Movability, Node}; use rustc_middle::hir::map::Map; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use rustc_span::hygiene::DesugaringKind; diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index cf8d9300a11..a849d61edfe 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -6,7 +6,7 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::Visitor; use rustc_hir::{ExprKind, InlineAsmOperand, StmtKind}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI; use rustc_span::symbol::sym; diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index a5f7b07fe52..160528e4074 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -13,7 +13,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::middle::privacy::{self, Level}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::CrateType; use rustc_target::spec::abi::Abi; diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index 9615f283ff4..f9060328f48 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -16,7 +16,8 @@ use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::nested_filter; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index}; -use rustc_middle::ty::{query::Providers, TyCtxt}; +use rustc_middle::query::Providers; +use rustc_middle::ty::TyCtxt; use rustc_session::lint; use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED}; use rustc_span::symbol::{sym, Symbol}; diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs index 605cf0a93b8..d87df706cc8 100644 --- a/compiler/rustc_passes/src/upvars.rs +++ b/compiler/rustc_passes/src/upvars.rs @@ -5,7 +5,7 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{self, HirId}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_span::Span; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d6eb5463870..7b39cb0a068 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -25,9 +25,9 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; -use rustc_middle::middle::privacy::{EffectiveVisibilities, Level}; +use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level}; +use rustc_middle::query::Providers; use rustc_middle::span_bug; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, Const, GenericParamDefKind}; use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; @@ -38,7 +38,7 @@ use rustc_span::Span; use std::marker::PhantomData; use std::ops::ControlFlow; -use std::{cmp, fmt, mem}; +use std::{fmt, mem}; use errors::{ FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface, @@ -408,8 +408,9 @@ impl VisibilityLike for ty::Visibility { min(find.tcx.local_visibility(def_id), find.min, find.tcx) } } -impl VisibilityLike for Option<Level> { - const MAX: Self = Some(Level::Direct); + +impl VisibilityLike for Option<EffectiveVisibility> { + const MAX: Self = Some(EffectiveVisibility::from_vis(ty::Visibility::Public)); // Type inference is very smart sometimes. // It can make an impl reachable even some components of its type or trait are unreachable. // E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }` @@ -421,7 +422,13 @@ impl VisibilityLike for Option<Level> { // (which require reaching the `DefId`s in them). const SHALLOW: bool = true; fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self { - cmp::min(find.effective_visibilities.public_at_level(def_id), find.min) + if let Some(min) = find.min { + return find + .effective_visibilities + .effective_vis(def_id) + .map(|eff_vis| min.min(*eff_vis, find.tcx)); + } + None } } @@ -447,49 +454,79 @@ struct EmbargoVisitor<'tcx> { /// n::p::f() /// } macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>, - /// Previous visibility level; `None` means unreachable. - prev_level: Option<Level>, /// Has something changed in the level map? changed: bool, } struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> { - level: Option<Level>, + effective_vis: Option<EffectiveVisibility>, item_def_id: LocalDefId, ev: &'a mut EmbargoVisitor<'tcx>, + level: Level, } impl<'tcx> EmbargoVisitor<'tcx> { - fn get(&self, def_id: LocalDefId) -> Option<Level> { - self.effective_visibilities.public_at_level(def_id) - } - - /// Updates node level and returns the updated level. - fn update(&mut self, def_id: LocalDefId, level: Option<Level>) -> Option<Level> { - let old_level = self.get(def_id); - // Visibility levels can only grow. - if level > old_level { - self.effective_visibilities.set_public_at_level( - def_id, - || ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)), - level.unwrap(), - ); - self.changed = true; - level - } else { - old_level + fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> { + self.effective_visibilities.effective_vis(def_id).copied() + } + + // Updates node effective visibility. + fn update( + &mut self, + def_id: LocalDefId, + inherited_effective_vis: Option<EffectiveVisibility>, + level: Level, + ) { + let nominal_vis = self.tcx.local_visibility(def_id); + self.update_eff_vis(def_id, inherited_effective_vis, Some(nominal_vis), level); + } + + fn update_eff_vis( + &mut self, + def_id: LocalDefId, + inherited_effective_vis: Option<EffectiveVisibility>, + nominal_vis: Option<ty::Visibility>, + level: Level, + ) { + if let Some(inherited_effective_vis) = inherited_effective_vis { + let private_vis = + ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)); + if Some(private_vis) != nominal_vis { + self.changed |= self.effective_visibilities.update( + def_id, + nominal_vis, + || private_vis, + inherited_effective_vis, + level, + self.tcx, + ); + } } } fn reach( &mut self, def_id: LocalDefId, - level: Option<Level>, + effective_vis: Option<EffectiveVisibility>, ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { ReachEverythingInTheInterfaceVisitor { - level: cmp::min(level, Some(Level::Reachable)), + effective_vis, item_def_id: def_id, ev: self, + level: Level::Reachable, + } + } + + fn reach_through_impl_trait( + &mut self, + def_id: LocalDefId, + effective_vis: Option<EffectiveVisibility>, + ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> { + ReachEverythingInTheInterfaceVisitor { + effective_vis, + item_def_id: def_id, + ev: self, + level: Level::ReachableThroughImplTrait, } } @@ -510,16 +547,18 @@ impl<'tcx> EmbargoVisitor<'tcx> { return; } - if self.get(local_def_id).is_none() { + if self.effective_visibilities.public_at_level(local_def_id).is_none() { return; } // Since we are starting from an externally visible module, // all the parents in the loop below are also guaranteed to be modules. let mut module_def_id = macro_module_def_id; + let macro_ev = self.get(local_def_id); + assert!(macro_ev.is_some()); loop { let changed_reachability = - self.update_macro_reachable(module_def_id, macro_module_def_id); + self.update_macro_reachable(module_def_id, macro_module_def_id, macro_ev); if changed_reachability || module_def_id == CRATE_DEF_ID { break; } @@ -533,21 +572,33 @@ impl<'tcx> EmbargoVisitor<'tcx> { &mut self, module_def_id: LocalDefId, defining_mod: LocalDefId, + macro_ev: Option<EffectiveVisibility>, ) -> bool { if self.macro_reachable.insert((module_def_id, defining_mod)) { - self.update_macro_reachable_mod(module_def_id, defining_mod); + self.update_macro_reachable_mod(module_def_id, defining_mod, macro_ev); true } else { false } } - fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod: LocalDefId) { + fn update_macro_reachable_mod( + &mut self, + module_def_id: LocalDefId, + defining_mod: LocalDefId, + macro_ev: Option<EffectiveVisibility>, + ) { let module = self.tcx.hir().get_module(module_def_id).0; for item_id in module.item_ids { let def_kind = self.tcx.def_kind(item_id.owner_id); let vis = self.tcx.local_visibility(item_id.owner_id.def_id); - self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod); + self.update_macro_reachable_def( + item_id.owner_id.def_id, + def_kind, + vis, + defining_mod, + macro_ev, + ); } for child in self.tcx.module_children_local(module_def_id) { // FIXME: Use module children for the logic above too. @@ -556,7 +607,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { && let Res::Def(def_kind, def_id) = child.res && let Some(def_id) = def_id.as_local() { let vis = self.tcx.local_visibility(def_id); - self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod); + self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev); } } } @@ -567,16 +618,14 @@ impl<'tcx> EmbargoVisitor<'tcx> { def_kind: DefKind, vis: ty::Visibility, module: LocalDefId, + macro_ev: Option<EffectiveVisibility>, ) { - let level = Some(Level::Reachable); - if vis.is_public() { - self.update(def_id, level); - } + self.update(def_id, macro_ev, Level::Reachable); match def_kind { // No type privacy, so can be directly marked as reachable. DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => { if vis.is_accessible_from(module, self.tcx) { - self.update(def_id, level); + self.update(def_id, macro_ev, Level::Reachable); } } @@ -588,7 +637,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { let item = self.tcx.hir().expect_item(def_id); if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind { if vis.is_accessible_from(module, self.tcx) { - self.update(def_id, level); + self.update(def_id, macro_ev, Level::Reachable); } } } @@ -599,26 +648,24 @@ impl<'tcx> EmbargoVisitor<'tcx> { // the module, however may be reachable. DefKind::Mod => { if vis.is_accessible_from(module, self.tcx) { - self.update_macro_reachable(def_id, module); + self.update_macro_reachable(def_id, module, macro_ev); } } DefKind::Struct | DefKind::Union => { // While structs and unions have type privacy, their fields do not. - if vis.is_public() { - let item = self.tcx.hir().expect_item(def_id); - if let hir::ItemKind::Struct(ref struct_def, _) - | hir::ItemKind::Union(ref struct_def, _) = item.kind - { - for field in struct_def.fields() { - let field_vis = self.tcx.local_visibility(field.def_id); - if field_vis.is_accessible_from(module, self.tcx) { - self.reach(field.def_id, level).ty(); - } + let item = self.tcx.hir().expect_item(def_id); + if let hir::ItemKind::Struct(ref struct_def, _) + | hir::ItemKind::Union(ref struct_def, _) = item.kind + { + for field in struct_def.fields() { + let field_vis = self.tcx.local_visibility(field.def_id); + if field_vis.is_accessible_from(module, self.tcx) { + self.reach(field.def_id, macro_ev).ty(); } - } else { - bug!("item {:?} with DefKind {:?}", item, def_kind); } + } else { + bug!("item {:?} with DefKind {:?}", item, def_kind); } } @@ -662,14 +709,16 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { - let item_level = match item.kind { + let item_ev = match item.kind { hir::ItemKind::Impl { .. } => { - let impl_level = Option::<Level>::of_impl( + let impl_ev = Option::<EffectiveVisibility>::of_impl( item.owner_id.def_id, self.tcx, &self.effective_visibilities, ); - self.update(item.owner_id.def_id, impl_level) + + self.update_eff_vis(item.owner_id.def_id, impl_ev, None, Level::Direct); + impl_ev } _ => self.get(item.owner_id.def_id), }; @@ -678,38 +727,35 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { match item.kind { hir::ItemKind::Enum(ref def, _) => { for variant in def.variants { - let variant_level = self.update(variant.def_id, item_level); + self.update(variant.def_id, item_ev, Level::Reachable); + let variant_ev = self.get(variant.def_id); if let Some(ctor_def_id) = variant.data.ctor_def_id() { - self.update(ctor_def_id, item_level); + self.update(ctor_def_id, variant_ev, Level::Reachable); } for field in variant.data.fields() { - self.update(field.def_id, variant_level); + self.update(field.def_id, variant_ev, Level::Reachable); } } } hir::ItemKind::Impl(ref impl_) => { for impl_item_ref in impl_.items { - if impl_.of_trait.is_some() - || self.tcx.visibility(impl_item_ref.id.owner_id).is_public() - { - self.update(impl_item_ref.id.owner_id.def_id, item_level); - } + let def_id = impl_item_ref.id.owner_id.def_id; + let nominal_vis = + impl_.of_trait.is_none().then(|| self.tcx.local_visibility(def_id)); + self.update_eff_vis(def_id, item_ev, nominal_vis, Level::Direct); } } hir::ItemKind::Trait(.., trait_item_refs) => { for trait_item_ref in trait_item_refs { - self.update(trait_item_ref.id.owner_id.def_id, item_level); + self.update(trait_item_ref.id.owner_id.def_id, item_ev, Level::Reachable); } } hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => { if let Some(ctor_def_id) = def.ctor_def_id() { - self.update(ctor_def_id, item_level); + self.update(ctor_def_id, item_ev, Level::Reachable); } for field in def.fields() { - let vis = self.tcx.visibility(field.def_id); - if vis.is_public() { - self.update(field.def_id, item_level); - } + self.update(field.def_id, item_ev, Level::Reachable); } } hir::ItemKind::Macro(ref macro_def, _) => { @@ -717,9 +763,7 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } hir::ItemKind::ForeignMod { items, .. } => { for foreign_item in items { - if self.tcx.visibility(foreign_item.id.owner_id).is_public() { - self.update(foreign_item.id.owner_id.def_id, item_level); - } + self.update(foreign_item.id.owner_id.def_id, item_ev, Level::Reachable); } } @@ -754,8 +798,11 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // FIXME: This is some serious pessimization intended to workaround deficiencies // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time // reachable if they are returned via `impl Trait`, even from private functions. - let exist_level = cmp::max(item_level, Some(Level::ReachableThroughImplTrait)); - self.reach(item.owner_id.def_id, exist_level).generics().predicates().ty(); + let exist_ev = Some(EffectiveVisibility::from_vis(ty::Visibility::Public)); + self.reach_through_impl_trait(item.owner_id.def_id, exist_ev) + .generics() + .predicates() + .ty(); } } // Visit everything. @@ -763,17 +810,18 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { | hir::ItemKind::Static(..) | hir::ItemKind::Fn(..) | hir::ItemKind::TyAlias(..) => { - if item_level.is_some() { - self.reach(item.owner_id.def_id, item_level).generics().predicates().ty(); + if item_ev.is_some() { + self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty(); } } hir::ItemKind::Trait(.., trait_item_refs) => { - if item_level.is_some() { - self.reach(item.owner_id.def_id, item_level).generics().predicates(); + if item_ev.is_some() { + self.reach(item.owner_id.def_id, item_ev).generics().predicates(); for trait_item_ref in trait_item_refs { let tcx = self.tcx; - let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_level); + let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_ev); + reach.generics().predicates(); if trait_item_ref.kind == AssocItemKind::Type @@ -787,23 +835,24 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } } hir::ItemKind::TraitAlias(..) => { - if item_level.is_some() { - self.reach(item.owner_id.def_id, item_level).generics().predicates(); + if item_ev.is_some() { + self.reach(item.owner_id.def_id, item_ev).generics().predicates(); } } // Visit everything except for private impl items. hir::ItemKind::Impl(ref impl_) => { - if item_level.is_some() { - self.reach(item.owner_id.def_id, item_level) + if item_ev.is_some() { + self.reach(item.owner_id.def_id, item_ev) .generics() .predicates() .ty() .trait_ref(); for impl_item_ref in impl_.items { - let impl_item_level = self.get(impl_item_ref.id.owner_id.def_id); - if impl_item_level.is_some() { - self.reach(impl_item_ref.id.owner_id.def_id, impl_item_level) + let impl_item_ev = self.get(impl_item_ref.id.owner_id.def_id); + + if impl_item_ev.is_some() { + self.reach(impl_item_ref.id.owner_id.def_id, impl_item_ev) .generics() .predicates() .ty(); @@ -814,23 +863,23 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // Visit everything, but enum variants have their own levels. hir::ItemKind::Enum(ref def, _) => { - if item_level.is_some() { - self.reach(item.owner_id.def_id, item_level).generics().predicates(); + if item_ev.is_some() { + self.reach(item.owner_id.def_id, item_ev).generics().predicates(); } for variant in def.variants { - let variant_level = self.get(variant.def_id); - if variant_level.is_some() { + let variant_ev = self.get(variant.def_id); + if variant_ev.is_some() { for field in variant.data.fields() { - self.reach(field.def_id, variant_level).ty(); + self.reach(field.def_id, variant_ev).ty(); } // Corner case: if the variant is reachable, but its // enum is not, make the enum reachable as well. - self.reach(item.owner_id.def_id, variant_level).ty(); + self.reach(item.owner_id.def_id, variant_ev).ty(); } if let Some(ctor_def_id) = variant.data.ctor_def_id() { - let ctor_level = self.get(ctor_def_id); - if ctor_level.is_some() { - self.reach(item.owner_id.def_id, ctor_level).ty(); + let ctor_ev = self.get(ctor_def_id); + if ctor_ev.is_some() { + self.reach(item.owner_id.def_id, ctor_ev).ty(); } } } @@ -838,9 +887,9 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { // Visit everything, but foreign items have their own levels. hir::ItemKind::ForeignMod { items, .. } => { for foreign_item in items { - let foreign_item_level = self.get(foreign_item.id.owner_id.def_id); - if foreign_item_level.is_some() { - self.reach(foreign_item.id.owner_id.def_id, foreign_item_level) + let foreign_item_ev = self.get(foreign_item.id.owner_id.def_id); + if foreign_item_ev.is_some() { + self.reach(foreign_item.id.owner_id.def_id, foreign_item_ev) .generics() .predicates() .ty(); @@ -849,36 +898,32 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> { } // Visit everything except for private fields. hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => { - if item_level.is_some() { - self.reach(item.owner_id.def_id, item_level).generics().predicates(); + if item_ev.is_some() { + self.reach(item.owner_id.def_id, item_ev).generics().predicates(); for field in struct_def.fields() { - let field_level = self.get(field.def_id); - if field_level.is_some() { - self.reach(field.def_id, field_level).ty(); + let field_ev = self.get(field.def_id); + if field_ev.is_some() { + self.reach(field.def_id, field_ev).ty(); } } } if let Some(ctor_def_id) = struct_def.ctor_def_id() { - let ctor_level = self.get(ctor_def_id); - if ctor_level.is_some() { - self.reach(item.owner_id.def_id, ctor_level).ty(); + let ctor_ev = self.get(ctor_def_id); + if ctor_ev.is_some() { + self.reach(item.owner_id.def_id, ctor_ev).ty(); } } } } - let orig_level = mem::replace(&mut self.prev_level, item_level); intravisit::walk_item(self, item); - self.prev_level = orig_level; } fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) { // Blocks can have public items, for example impls, but they always // start as completely private regardless of publicity of a function, // constant, type, field, etc., in which this block resides. - let orig_level = mem::replace(&mut self.prev_level, None); intravisit::walk_block(self, b); - self.prev_level = orig_level; } } @@ -932,11 +977,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx> _descr: &dyn fmt::Display, ) -> ControlFlow<Self::BreakTy> { if let Some(def_id) = def_id.as_local() { - if let (ty::Visibility::Public, _) | (_, Some(Level::ReachableThroughImplTrait)) = - (self.tcx().visibility(def_id.to_def_id()), self.level) - { - self.ev.update(def_id, self.level); - } + self.ev.update_eff_vis(def_id, self.effective_vis, None, self.level); } ControlFlow::Continue(()) } @@ -2164,7 +2205,6 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities { tcx, effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(), macro_reachable: Default::default(), - prev_level: Some(Level::Direct), changed: false, }; diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml index b107a3f03fe..e596993465c 100644 --- a/compiler/rustc_query_impl/Cargo.toml +++ b/compiler/rustc_query_impl/Cargo.toml @@ -7,6 +7,8 @@ edition = "2021" [dependencies] +memoffset = { version = "0.6.0", features = ["unstable_const"] } +field-offset = "0.3.5" measureme = "10.0.0" rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs index 82b335f4b4b..4cf0f1305a7 100644 --- a/compiler/rustc_query_impl/src/lib.rs +++ b/compiler/rustc_query_impl/src/lib.rs @@ -3,28 +3,42 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] // this shouldn't be necessary, but the check for `&mut _` is too naive and denies returning a function pointer that takes a mut ref #![feature(const_mut_refs)] +#![feature(const_refs_to_cell)] #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] #![recursion_limit = "256"] -#![allow(rustc::potential_query_instability)] +#![allow(rustc::potential_query_instability, unused_parens)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] #[macro_use] extern crate rustc_middle; -use crate::plumbing::{encode_all_query_results, try_mark_green}; +use crate::plumbing::{__rust_begin_short_backtrace, encode_all_query_results, try_mark_green}; +use field_offset::offset_of; +use rustc_data_structures::stable_hasher::HashStable; +use rustc_data_structures::sync::AtomicU64; use rustc_middle::arena::Arena; +use rustc_middle::dep_graph::DepNodeIndex; use rustc_middle::dep_graph::{self, DepKind, DepKindStruct}; use rustc_middle::query::erase::{erase, restore, Erase}; +use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache}; +use rustc_middle::query::plumbing::{ + DynamicQuery, QueryKeyStringCache, QuerySystem, QuerySystemFns, +}; use rustc_middle::query::AsLocalKey; -use rustc_middle::ty::query::{ - query_keys, query_provided, query_provided_to_value, query_storage, query_values, +use rustc_middle::query::{ + queries, DynamicQueries, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates, }; -use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine, QuerySystemFns}; use rustc_middle::ty::TyCtxt; use rustc_query_system::dep_graph::SerializedDepNodeIndex; +use rustc_query_system::ich::StableHashingContext; +use rustc_query_system::query::{ + get_query_incr, get_query_non_incr, HashResult, QueryCache, QueryConfig, QueryInfo, QueryMap, + QueryMode, QueryState, +}; +use rustc_query_system::HandleCycleError; use rustc_query_system::Value; use rustc_span::Span; @@ -32,31 +46,182 @@ use rustc_span::Span; mod plumbing; pub use crate::plumbing::QueryCtxt; -pub use rustc_query_system::query::QueryConfig; -use rustc_query_system::query::*; - mod profiling_support; pub use self::profiling_support::alloc_self_profile_query_strings; -/// This is implemented per query and restoring query values from their erased state. -trait QueryConfigRestored<'tcx>: QueryConfig<QueryCtxt<'tcx>> + Default { - type RestoredValue; +struct DynamicConfig< + 'tcx, + C: QueryCache, + const ANON: bool, + const DEPTH_LIMIT: bool, + const FEEDABLE: bool, +> { + dynamic: &'tcx DynamicQuery<'tcx, C>, +} - fn restore(value: <Self as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue; +impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Copy + for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE> +{ +} +impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Clone + for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE> +{ + fn clone(&self) -> Self { + DynamicConfig { dynamic: self.dynamic } + } } -rustc_query_append! { define_queries! } +impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> + QueryConfig<QueryCtxt<'tcx>> for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE> +where + for<'a> C::Key: HashStable<StableHashingContext<'a>>, +{ + type Key = C::Key; + type Value = C::Value; + type Cache = C; + + #[inline(always)] + fn name(self) -> &'static str { + self.dynamic.name + } -pub fn query_system_fns<'tcx>( + #[inline(always)] + fn cache_on_disk(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool { + (self.dynamic.cache_on_disk)(tcx, key) + } + + #[inline(always)] + fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key, DepKind> + where + QueryCtxt<'tcx>: 'a, + { + self.dynamic.query_state.apply(&qcx.tcx.query_system.states) + } + + #[inline(always)] + fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache + where + 'tcx: 'a, + { + self.dynamic.query_cache.apply(&qcx.tcx.query_system.caches) + } + + #[inline(always)] + fn execute_query(self, tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value { + (self.dynamic.execute_query)(tcx, key) + } + + #[inline(always)] + fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value { + (self.dynamic.compute)(qcx.tcx, key) + } + + #[inline(always)] + fn try_load_from_disk( + self, + qcx: QueryCtxt<'tcx>, + key: &Self::Key, + prev_index: SerializedDepNodeIndex, + index: DepNodeIndex, + ) -> Option<Self::Value> { + if self.dynamic.can_load_from_disk { + (self.dynamic.try_load_from_disk)(qcx.tcx, key, prev_index, index) + } else { + None + } + } + + #[inline] + fn loadable_from_disk( + self, + qcx: QueryCtxt<'tcx>, + key: &Self::Key, + index: SerializedDepNodeIndex, + ) -> bool { + (self.dynamic.loadable_from_disk)(qcx.tcx, key, index) + } + + fn value_from_cycle_error( + self, + tcx: TyCtxt<'tcx>, + cycle: &[QueryInfo<DepKind>], + ) -> Self::Value { + (self.dynamic.value_from_cycle_error)(tcx, cycle) + } + + #[inline(always)] + fn format_value(self) -> fn(&Self::Value) -> String { + self.dynamic.format_value + } + + #[inline(always)] + fn anon(self) -> bool { + ANON + } + + #[inline(always)] + fn eval_always(self) -> bool { + self.dynamic.eval_always + } + + #[inline(always)] + fn depth_limit(self) -> bool { + DEPTH_LIMIT + } + + #[inline(always)] + fn feedable(self) -> bool { + FEEDABLE + } + + #[inline(always)] + fn dep_kind(self) -> DepKind { + self.dynamic.dep_kind + } + + #[inline(always)] + fn handle_cycle_error(self) -> HandleCycleError { + self.dynamic.handle_cycle_error + } + + #[inline(always)] + fn hash_result(self) -> HashResult<Self::Value> { + self.dynamic.hash_result + } +} + +/// This is implemented per query. It allows restoring query values from their erased state +/// and constructing a QueryConfig. +trait QueryConfigRestored<'tcx> { + type RestoredValue; + type Config: QueryConfig<QueryCtxt<'tcx>>; + + fn config(tcx: TyCtxt<'tcx>) -> Self::Config; + fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value) + -> Self::RestoredValue; +} + +pub fn query_system<'tcx>( local_providers: Providers, extern_providers: ExternProviders, -) -> QuerySystemFns<'tcx> { - QuerySystemFns { - engine: engine(), - local_providers, - extern_providers, - query_structs: make_dep_kind_array!(query_structs).to_vec(), - encode_query_results: encode_all_query_results, - try_mark_green: try_mark_green, + on_disk_cache: Option<OnDiskCache<'tcx>>, + incremental: bool, +) -> QuerySystem<'tcx> { + QuerySystem { + states: Default::default(), + arenas: Default::default(), + caches: Default::default(), + dynamic_queries: dynamic_queries(), + on_disk_cache, + fns: QuerySystemFns { + engine: engine(incremental), + local_providers, + extern_providers, + encode_query_results: encode_all_query_results, + try_mark_green: try_mark_green, + }, + jobs: AtomicU64::new(1), } } + +rustc_query_append! { define_queries! } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index 9f8ac7ccd0b..244f0e84b43 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -4,6 +4,7 @@ use crate::rustc_middle::dep_graph::DepContext; use crate::rustc_middle::ty::TyEncoder; +use crate::QueryConfigRestored; use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher}; use rustc_data_structures::sync::Lock; use rustc_errors::Diagnostic; @@ -80,8 +81,8 @@ impl QueryContext for QueryCtxt<'_> { fn try_collect_active_jobs(self) -> Option<QueryMap<DepKind>> { let mut jobs = QueryMap::default(); - for query in &self.query_system.fns.query_structs { - (query.try_collect_active_jobs)(self.tcx, &mut jobs); + for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() { + collect(self.tcx, &mut jobs); } Some(jobs) @@ -182,10 +183,8 @@ pub(super) fn encode_all_query_results<'tcx>( encoder: &mut CacheEncoder<'_, 'tcx>, query_result_index: &mut EncodedDepNodeIndex, ) { - for query in &tcx.query_system.fns.query_structs { - if let Some(encode) = query.encode_query_results { - encode(tcx, encoder, query_result_index); - } + for encode in super::ENCODE_QUERY_RESULTS.iter().copied().filter_map(|e| e) { + encode(tcx, encoder, query_result_index); } } @@ -265,14 +264,14 @@ macro_rules! hash_result { } macro_rules! call_provider { - ([][$qcx:expr, $name:ident, $key:expr]) => {{ - ($qcx.query_system.fns.local_providers.$name)($qcx, $key) + ([][$tcx:expr, $name:ident, $key:expr]) => {{ + ($tcx.query_system.fns.local_providers.$name)($tcx, $key) }}; - ([(separate_provide_extern) $($rest:tt)*][$qcx:expr, $name:ident, $key:expr]) => {{ + ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{ if let Some(key) = $key.as_local_key() { - ($qcx.query_system.fns.local_providers.$name)($qcx, key) + ($tcx.query_system.fns.local_providers.$name)($tcx, key) } else { - ($qcx.query_system.fns.extern_providers.$name)($qcx, $key) + ($tcx.query_system.fns.extern_providers.$name)($tcx, $key) } }}; ([$other:tt $($modifiers:tt)*][$($args:tt)*]) => { @@ -341,7 +340,7 @@ pub(crate) fn create_query_frame< } pub(crate) fn encode_query_results<'a, 'tcx, Q>( - query: Q, + query: Q::Config, qcx: QueryCtxt<'tcx>, encoder: &mut CacheEncoder<'a, 'tcx>, query_result_index: &mut EncodedDepNodeIndex, @@ -392,12 +391,26 @@ pub(crate) fn loadable_from_disk<'tcx>(tcx: TyCtxt<'tcx>, id: SerializedDepNodeI pub(crate) fn try_load_from_disk<'tcx, V>( tcx: TyCtxt<'tcx>, - id: SerializedDepNodeIndex, + prev_index: SerializedDepNodeIndex, + index: DepNodeIndex, ) -> Option<V> where V: for<'a> Decodable<CacheDecoder<'a, 'tcx>>, { - tcx.query_system.on_disk_cache.as_ref()?.try_load_query_result(tcx, id) + let on_disk_cache = tcx.query_system.on_disk_cache.as_ref()?; + + let prof_timer = tcx.prof.incr_cache_loading(); + + // The call to `with_query_deserialization` enforces that no new `DepNodes` + // are created during deserialization. See the docs of that method for more + // details. + let value = tcx + .dep_graph + .with_query_deserialization(|| on_disk_cache.try_load_query_result(tcx, prev_index)); + + prof_timer.finish_with_query_invocation_id(index.into()); + + value } fn force_from_dep_node<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool @@ -434,10 +447,9 @@ where pub(crate) fn query_callback<'tcx, Q>(is_anon: bool, is_eval_always: bool) -> DepKindStruct<'tcx> where - Q: QueryConfig<QueryCtxt<'tcx>> + Default, - Q::Key: DepNodeParams<TyCtxt<'tcx>>, + Q: QueryConfigRestored<'tcx>, { - let fingerprint_style = Q::Key::fingerprint_style(); + let fingerprint_style = <Q::Config as QueryConfig<QueryCtxt<'tcx>>>::Key::fingerprint_style(); if is_anon || !fingerprint_style.reconstructible() { return DepKindStruct { @@ -453,13 +465,25 @@ where is_anon, is_eval_always, fingerprint_style, - force_from_dep_node: Some(|tcx, dep_node| force_from_dep_node(Q::default(), tcx, dep_node)), + force_from_dep_node: Some(|tcx, dep_node| { + force_from_dep_node(Q::config(tcx), tcx, dep_node) + }), try_load_from_on_disk_cache: Some(|tcx, dep_node| { - try_load_from_on_disk_cache(Q::default(), tcx, dep_node) + try_load_from_on_disk_cache(Q::config(tcx), tcx, dep_node) }), } } +macro_rules! item_if_cached { + ([] $tokens:tt) => {}; + ([(cache) $($rest:tt)*] { $($tokens:tt)* }) => { + $($tokens)* + }; + ([$other:tt $($modifiers:tt)*] $tokens:tt) => { + item_if_cached! { [$($modifiers)*] $tokens } + }; +} + macro_rules! expand_if_cached { ([], $tokens:expr) => {{ None @@ -472,193 +496,226 @@ macro_rules! expand_if_cached { }; } +/// Don't show the backtrace for query system by default +/// use `RUST_BACKTRACE=full` to show all the backtraces +#[inline(never)] +pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T +where + F: FnOnce() -> T, +{ + let result = f(); + std::hint::black_box(()); + result +} + // NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros // invoked by `rustc_query_append`. macro_rules! define_queries { ( $($(#[$attr:meta])* [$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => { - mod get_query { - use super::*; - $( - #[inline(always)] - #[tracing::instrument(level = "trace", skip(tcx))] - pub(super) fn $name<'tcx>( + pub(crate) mod query_impl { $(pub mod $name { + use super::super::*; + use std::marker::PhantomData; + + pub mod get_query_incr { + use super::*; + + // Adding `__rust_end_short_backtrace` marker to backtraces so that we emit the frames + // when `RUST_BACKTRACE=1`, add a new mod with `$name` here is to allow duplicate naming + #[inline(never)] + pub fn __rust_end_short_backtrace<'tcx>( tcx: TyCtxt<'tcx>, span: Span, - key: query_keys::$name<'tcx>, + key: queries::$name::Key<'tcx>, mode: QueryMode, - ) -> Option<Erase<query_values::$name<'tcx>>> { - get_query( - queries::$name::default(), + ) -> Option<Erase<queries::$name::Value<'tcx>>> { + get_query_incr( + QueryType::config(tcx), QueryCtxt::new(tcx), span, key, mode ) } - )* - } - - pub(crate) fn engine() -> QueryEngine { - QueryEngine { - $($name: get_query::$name,)* } - } - #[allow(nonstandard_style)] - mod queries { - use std::marker::PhantomData; + pub mod get_query_non_incr { + use super::*; - $( - #[derive(Copy, Clone, Default)] - pub struct $name<'tcx> { - data: PhantomData<&'tcx ()> + #[inline(never)] + pub fn __rust_end_short_backtrace<'tcx>( + tcx: TyCtxt<'tcx>, + span: Span, + key: queries::$name::Key<'tcx>, + __mode: QueryMode, + ) -> Option<Erase<queries::$name::Value<'tcx>>> { + Some(get_query_non_incr( + QueryType::config(tcx), + QueryCtxt::new(tcx), + span, + key, + )) } - )* - } - - $(impl<'tcx> QueryConfig<QueryCtxt<'tcx>> for queries::$name<'tcx> { - type Key = query_keys::$name<'tcx>; - type Value = Erase<query_values::$name<'tcx>>; - - #[inline(always)] - fn name(self) -> &'static str { - stringify!($name) - } - - #[inline] - fn format_value(self) -> fn(&Self::Value) -> String { - |value| format!("{:?}", restore::<query_values::$name<'tcx>>(*value)) - } - - #[inline] - fn cache_on_disk(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool { - ::rustc_middle::query::cached::$name(tcx, key) } - type Cache = query_storage::$name<'tcx>; - - #[inline(always)] - fn query_state<'a>(self, tcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key, crate::dep_graph::DepKind> - where QueryCtxt<'tcx>: 'a - { - &tcx.query_system.states.$name + pub fn dynamic_query<'tcx>() -> DynamicQuery<'tcx, queries::$name::Storage<'tcx>> { + DynamicQuery { + name: stringify!($name), + eval_always: is_eval_always!([$($modifiers)*]), + dep_kind: dep_graph::DepKind::$name, + handle_cycle_error: handle_cycle_error!([$($modifiers)*]), + query_state: offset_of!(QueryStates<'tcx> => $name), + query_cache: offset_of!(QueryCaches<'tcx> => $name), + cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key), + execute_query: |tcx, key| erase(tcx.$name(key)), + compute: |tcx, key| { + __rust_begin_short_backtrace(|| + queries::$name::provided_to_erased( + tcx, + call_provider!([$($modifiers)*][tcx, $name, key]) + ) + ) + }, + can_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] true false), + try_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] { + |tcx, key, prev_index, index| { + if ::rustc_middle::query::cached::$name(tcx, key) { + let value = $crate::plumbing::try_load_from_disk::< + queries::$name::ProvidedValue<'tcx> + >( + tcx, + prev_index, + index, + ); + value.map(|value| queries::$name::provided_to_erased(tcx, value)) + } else { + None + } + } + } { + |_tcx, _key, _prev_index, _index| None + }), + value_from_cycle_error: |tcx, cycle| { + let result: queries::$name::Value<'tcx> = Value::from_cycle_error(tcx, cycle); + erase(result) + }, + loadable_from_disk: |_tcx, _key, _index| { + should_ever_cache_on_disk!([$($modifiers)*] { + ::rustc_middle::query::cached::$name(_tcx, _key) && + $crate::plumbing::loadable_from_disk(_tcx, _index) + } { + false + }) + }, + hash_result: hash_result!([$($modifiers)*][queries::$name::Value<'tcx>]), + format_value: |value| format!("{:?}", restore::<queries::$name::Value<'tcx>>(*value)), + } } - #[inline(always)] - fn query_cache<'a>(self, tcx: QueryCtxt<'tcx>) -> &'a Self::Cache - where 'tcx:'a - { - &tcx.query_system.caches.$name + #[derive(Copy, Clone, Default)] + pub struct QueryType<'tcx> { + data: PhantomData<&'tcx ()> } - fn execute_query(self, tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value { - erase(tcx.$name(key)) - } + impl<'tcx> QueryConfigRestored<'tcx> for QueryType<'tcx> { + type RestoredValue = queries::$name::Value<'tcx>; + type Config = DynamicConfig< + 'tcx, + queries::$name::Storage<'tcx>, + { is_anon!([$($modifiers)*]) }, + { depth_limit!([$($modifiers)*]) }, + { feedable!([$($modifiers)*]) }, + >; - #[inline] - #[allow(unused_variables)] - fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value { - query_provided_to_value::$name( - qcx.tcx, - call_provider!([$($modifiers)*][qcx.tcx, $name, key]) - ) - } - - #[inline] - fn try_load_from_disk( - self, - _qcx: QueryCtxt<'tcx>, - _key: &Self::Key - ) -> rustc_query_system::query::TryLoadFromDisk<QueryCtxt<'tcx>, Self::Value> { - should_ever_cache_on_disk!([$($modifiers)*] { - if ::rustc_middle::query::cached::$name(_qcx.tcx, _key) { - Some(|qcx: QueryCtxt<'tcx>, dep_node| { - let value = $crate::plumbing::try_load_from_disk::<query_provided::$name<'tcx>>( - qcx.tcx, - dep_node - ); - value.map(|value| query_provided_to_value::$name(qcx.tcx, value)) - }) - } else { - None + #[inline(always)] + fn config(tcx: TyCtxt<'tcx>) -> Self::Config { + DynamicConfig { + dynamic: &tcx.query_system.dynamic_queries.$name, } - } { - None - }) - } - - #[inline] - fn loadable_from_disk( - self, - _qcx: QueryCtxt<'tcx>, - _key: &Self::Key, - _index: SerializedDepNodeIndex, - ) -> bool { - should_ever_cache_on_disk!([$($modifiers)*] { - self.cache_on_disk(_qcx.tcx, _key) && - $crate::plumbing::loadable_from_disk(_qcx.tcx, _index) - } { - false - }) - } + } - #[inline] - fn value_from_cycle_error( - self, - tcx: TyCtxt<'tcx>, - cycle: &[QueryInfo<DepKind>], - ) -> Self::Value { - let result: query_values::$name<'tcx> = Value::from_cycle_error(tcx, cycle); - erase(result) + #[inline(always)] + fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue { + restore::<queries::$name::Value<'tcx>>(value) + } } - #[inline(always)] - fn anon(self) -> bool { - is_anon!([$($modifiers)*]) + pub fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap<DepKind>) { + let make_query = |tcx, key| { + let kind = rustc_middle::dep_graph::DepKind::$name; + let name = stringify!($name); + $crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name) + }; + tcx.query_system.states.$name.try_collect_active_jobs( + tcx, + make_query, + qmap, + ).unwrap(); } - #[inline(always)] - fn eval_always(self) -> bool { - is_eval_always!([$($modifiers)*]) + pub fn alloc_self_profile_query_strings<'tcx>(tcx: TyCtxt<'tcx>, string_cache: &mut QueryKeyStringCache) { + $crate::profiling_support::alloc_self_profile_query_strings_for_query_cache( + tcx, + stringify!($name), + &tcx.query_system.caches.$name, + string_cache, + ) } - #[inline(always)] - fn depth_limit(self) -> bool { - depth_limit!([$($modifiers)*]) - } + item_if_cached! { [$($modifiers)*] { + pub fn encode_query_results<'tcx>( + tcx: TyCtxt<'tcx>, + encoder: &mut CacheEncoder<'_, 'tcx>, + query_result_index: &mut EncodedDepNodeIndex + ) { + $crate::plumbing::encode_query_results::<query_impl::$name::QueryType<'tcx>>( + query_impl::$name::QueryType::config(tcx), + QueryCtxt::new(tcx), + encoder, + query_result_index, + ) + } + }} + })*} - #[inline(always)] - fn feedable(self) -> bool { - feedable!([$($modifiers)*]) + pub(crate) fn engine(incremental: bool) -> QueryEngine { + if incremental { + QueryEngine { + $($name: query_impl::$name::get_query_incr::__rust_end_short_backtrace,)* + } + } else { + QueryEngine { + $($name: query_impl::$name::get_query_non_incr::__rust_end_short_backtrace,)* + } } + } - #[inline(always)] - fn dep_kind(self) -> rustc_middle::dep_graph::DepKind { - dep_graph::DepKind::$name + pub fn dynamic_queries<'tcx>() -> DynamicQueries<'tcx> { + DynamicQueries { + $( + $name: query_impl::$name::dynamic_query(), + )* } + } - #[inline(always)] - fn handle_cycle_error(self) -> rustc_query_system::HandleCycleError { - handle_cycle_error!([$($modifiers)*]) - } + // These arrays are used for iteration and can't be indexed by `DepKind`. - #[inline(always)] - fn hash_result(self) -> rustc_query_system::query::HashResult<Self::Value> { - hash_result!([$($modifiers)*][query_values::$name<'tcx>]) - } - })* + const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap<DepKind>)] = + &[$(query_impl::$name::try_collect_active_jobs),*]; - $(impl<'tcx> QueryConfigRestored<'tcx> for queries::$name<'tcx> { - type RestoredValue = query_values::$name<'tcx>; + const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[ + for<'tcx> fn(TyCtxt<'tcx>, &mut QueryKeyStringCache) + ] = &[$(query_impl::$name::alloc_self_profile_query_strings),*]; - #[inline(always)] - fn restore(value: <Self as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue { - restore::<query_values::$name<'tcx>>(value) - } - })* + const ENCODE_QUERY_RESULTS: &[ + Option<for<'tcx> fn( + TyCtxt<'tcx>, + &mut CacheEncoder<'_, 'tcx>, + &mut EncodedDepNodeIndex) + > + ] = &[$(expand_if_cached!([$($modifiers)*], query_impl::$name::encode_query_results)),*]; #[allow(nonstandard_style)] mod query_callbacks { @@ -718,71 +775,13 @@ macro_rules! define_queries { } $(pub(crate) fn $name<'tcx>()-> DepKindStruct<'tcx> { - $crate::plumbing::query_callback::<queries::$name<'tcx>>( + $crate::plumbing::query_callback::<query_impl::$name::QueryType<'tcx>>( is_anon!([$($modifiers)*]), is_eval_always!([$($modifiers)*]), ) })* } - mod query_structs { - use super::*; - use rustc_middle::ty::query::QueryStruct; - use rustc_middle::ty::query::QueryKeyStringCache; - use rustc_middle::dep_graph::DepKind; - - pub(super) const fn dummy_query_struct<'tcx>() -> QueryStruct<'tcx> { - fn noop_try_collect_active_jobs(_: TyCtxt<'_>, _: &mut QueryMap<DepKind>) -> Option<()> { - None - } - fn noop_alloc_self_profile_query_strings(_: TyCtxt<'_>, _: &mut QueryKeyStringCache) {} - - QueryStruct { - try_collect_active_jobs: noop_try_collect_active_jobs, - alloc_self_profile_query_strings: noop_alloc_self_profile_query_strings, - encode_query_results: None, - } - } - - pub(super) use dummy_query_struct as Null; - pub(super) use dummy_query_struct as Red; - pub(super) use dummy_query_struct as TraitSelect; - pub(super) use dummy_query_struct as CompileCodegenUnit; - pub(super) use dummy_query_struct as CompileMonoItem; - - $( - pub(super) const fn $name<'tcx>() -> QueryStruct<'tcx> { QueryStruct { - try_collect_active_jobs: |tcx, qmap| { - let make_query = |tcx, key| { - let kind = rustc_middle::dep_graph::DepKind::$name; - let name = stringify!($name); - $crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name) - }; - tcx.query_system.states.$name.try_collect_active_jobs( - tcx, - make_query, - qmap, - ) - }, - alloc_self_profile_query_strings: |tcx, string_cache| { - $crate::profiling_support::alloc_self_profile_query_strings_for_query_cache( - tcx, - stringify!($name), - &tcx.query_system.caches.$name, - string_cache, - ) - }, - encode_query_results: expand_if_cached!([$($modifiers)*], |tcx, encoder, query_result_index| - $crate::plumbing::encode_query_results::<super::queries::$name<'tcx>>( - super::queries::$name::default(), - QueryCtxt::new(tcx), - encoder, - query_result_index, - ) - ), - }})* - } - pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] { arena.alloc_from_iter(make_dep_kind_array!(query_callbacks)) } diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs index 7d9306f8087..fbc6db93e01 100644 --- a/compiler/rustc_query_impl/src/profiling_support.rs +++ b/compiler/rustc_query_impl/src/profiling_support.rs @@ -2,7 +2,7 @@ use measureme::{StringComponent, StringId}; use rustc_data_structures::profiling::SelfProfiler; use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE}; use rustc_hir::definitions::DefPathData; -use rustc_middle::ty::query::QueryKeyStringCache; +use rustc_middle::query::plumbing::QueryKeyStringCache; use rustc_middle::ty::TyCtxt; use rustc_query_system::query::QueryCache; use std::fmt::Debug; @@ -243,7 +243,7 @@ pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) { let mut string_cache = QueryKeyStringCache::new(); - for query in &tcx.query_system.fns.query_structs { - (query.alloc_self_profile_query_strings)(tcx, &mut string_cache); + for alloc in super::ALLOC_SELF_PROFILE_QUERY_STRINGS.iter() { + alloc(tcx, &mut string_cache) } } diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs index bb9ea50a1ea..7e47d701205 100644 --- a/compiler/rustc_query_system/src/query/config.rs +++ b/compiler/rustc_query_system/src/query/config.rs @@ -4,6 +4,7 @@ use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex}; use crate::error::HandleCycleError; use crate::ich::StableHashingContext; use crate::query::caches::QueryCache; +use crate::query::DepNodeIndex; use crate::query::{QueryContext, QueryInfo, QueryState}; use rustc_data_structures::fingerprint::Fingerprint; @@ -12,8 +13,6 @@ use std::hash::Hash; pub type HashResult<V> = Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>; -pub type TryLoadFromDisk<Qcx, V> = Option<fn(Qcx, SerializedDepNodeIndex) -> Option<V>>; - pub trait QueryConfig<Qcx: QueryContext>: Copy { fn name(self) -> &'static str; @@ -43,7 +42,13 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy { fn compute(self, tcx: Qcx, key: Self::Key) -> Self::Value; - fn try_load_from_disk(self, qcx: Qcx, idx: &Self::Key) -> TryLoadFromDisk<Qcx, Self::Value>; + fn try_load_from_disk( + self, + tcx: Qcx, + key: &Self::Key, + prev_index: SerializedDepNodeIndex, + index: DepNodeIndex, + ) -> Option<Self::Value>; fn loadable_from_disk(self, qcx: Qcx, key: &Self::Key, idx: SerializedDepNodeIndex) -> bool; diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs index fa1f51b04da..f7619d75be7 100644 --- a/compiler/rustc_query_system/src/query/mod.rs +++ b/compiler/rustc_query_system/src/query/mod.rs @@ -12,7 +12,7 @@ pub use self::caches::{ }; mod config; -pub use self::config::{HashResult, QueryConfig, TryLoadFromDisk}; +pub use self::config::{HashResult, QueryConfig}; use crate::dep_graph::DepKind; use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex}; diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 3b17c665fb7..730e4c8d30d 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -312,7 +312,7 @@ where } #[inline(never)] -fn try_execute_query<Q, Qcx>( +fn try_execute_query<Q, Qcx, const INCR: bool>( query: Q, qcx: Qcx, span: Span, @@ -355,7 +355,7 @@ where // Drop the lock before we start executing the query drop(state_lock); - execute_job(query, qcx, state, key, id, dep_node) + execute_job::<_, _, INCR>(query, qcx, state, key, id, dep_node) } Entry::Occupied(mut entry) => { match entry.get_mut() { @@ -383,7 +383,7 @@ where } #[inline(always)] -fn execute_job<Q, Qcx>( +fn execute_job<Q, Qcx, const INCR: bool>( query: Q, qcx: Qcx, state: &QueryState<Q::Key, Qcx::DepKind>, @@ -398,9 +398,19 @@ where // Use `JobOwner` so the query will be poisoned if executing it panics. let job_owner = JobOwner { state, key }; - let (result, dep_node_index) = match qcx.dep_context().dep_graph().data() { - None => execute_job_non_incr(query, qcx, key, id), - Some(data) => execute_job_incr(query, qcx, data, key, dep_node, id), + debug_assert_eq!(qcx.dep_context().dep_graph().is_fully_enabled(), INCR); + + let (result, dep_node_index) = if INCR { + execute_job_incr( + query, + qcx, + qcx.dep_context().dep_graph().data().unwrap(), + key, + dep_node, + id, + ) + } else { + execute_job_non_incr(query, qcx, key, id) }; let cache = query.query_cache(qcx); @@ -423,16 +433,22 @@ where (hasher(&mut hcx, &cached_result), hasher(&mut hcx, &result)) }); let formatter = query.format_value(); - debug_assert_eq!( - old_hash, - new_hash, - "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\ - computed={:#?}\nfed={:#?}", - query.dep_kind(), - key, - formatter(&result), - formatter(&cached_result), - ); + if old_hash != new_hash { + // We have an inconsistency. This can happen if one of the two + // results is tainted by errors. In this case, delay a bug to + // ensure compilation is doomed. + qcx.dep_context().sess().delay_span_bug( + DUMMY_SP, + format!( + "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\ + computed={:#?}\nfed={:#?}", + query.dep_kind(), + key, + formatter(&result), + formatter(&cached_result), + ), + ); + } } } job_owner.complete(cache, result, dep_node_index); @@ -564,59 +580,44 @@ where // First we try to load the result from the on-disk cache. // Some things are never cached on disk. - if let Some(try_load_from_disk) = query.try_load_from_disk(qcx, &key) { - let prof_timer = qcx.dep_context().profiler().incr_cache_loading(); - - // The call to `with_query_deserialization` enforces that no new `DepNodes` - // are created during deserialization. See the docs of that method for more - // details. - let result = qcx - .dep_context() - .dep_graph() - .with_query_deserialization(|| try_load_from_disk(qcx, prev_dep_node_index)); - - prof_timer.finish_with_query_invocation_id(dep_node_index.into()); - - if let Some(result) = result { - if std::intrinsics::unlikely( - qcx.dep_context().sess().opts.unstable_opts.query_dep_graph, - ) { - dep_graph_data.mark_debug_loaded_from_disk(*dep_node) - } - - let prev_fingerprint = dep_graph_data.prev_fingerprint_of(prev_dep_node_index); - // If `-Zincremental-verify-ich` is specified, re-hash results from - // the cache and make sure that they have the expected fingerprint. - // - // If not, we still seek to verify a subset of fingerprints loaded - // from disk. Re-hashing results is fairly expensive, so we can't - // currently afford to verify every hash. This subset should still - // give us some coverage of potential bugs though. - let try_verify = prev_fingerprint.split().1.as_u64() % 32 == 0; - if std::intrinsics::unlikely( - try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich, - ) { - incremental_verify_ich( - *qcx.dep_context(), - dep_graph_data, - &result, - prev_dep_node_index, - query.hash_result(), - query.format_value(), - ); - } + if let Some(result) = query.try_load_from_disk(qcx, key, prev_dep_node_index, dep_node_index) { + if std::intrinsics::unlikely(qcx.dep_context().sess().opts.unstable_opts.query_dep_graph) { + dep_graph_data.mark_debug_loaded_from_disk(*dep_node) + } - return Some((result, dep_node_index)); + let prev_fingerprint = dep_graph_data.prev_fingerprint_of(prev_dep_node_index); + // If `-Zincremental-verify-ich` is specified, re-hash results from + // the cache and make sure that they have the expected fingerprint. + // + // If not, we still seek to verify a subset of fingerprints loaded + // from disk. Re-hashing results is fairly expensive, so we can't + // currently afford to verify every hash. This subset should still + // give us some coverage of potential bugs though. + let try_verify = prev_fingerprint.split().1.as_u64() % 32 == 0; + if std::intrinsics::unlikely( + try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich, + ) { + incremental_verify_ich( + *qcx.dep_context(), + dep_graph_data, + &result, + prev_dep_node_index, + query.hash_result(), + query.format_value(), + ); } - // We always expect to find a cached result for things that - // can be forced from `DepNode`. - debug_assert!( - !qcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(), - "missing on-disk cache entry for reconstructible {dep_node:?}" - ); + return Some((result, dep_node_index)); } + // We always expect to find a cached result for things that + // can be forced from `DepNode`. + debug_assert!( + !query.cache_on_disk(*qcx.dep_context(), key) + || !qcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(), + "missing on-disk cache entry for {dep_node:?}" + ); + // Sanity check for the logic in `ensure`: if the node is green and the result loadable, // we should actually be able to load it. debug_assert!( @@ -799,7 +800,18 @@ pub enum QueryMode { } #[inline(always)] -pub fn get_query<Q, Qcx>( +pub fn get_query_non_incr<Q, Qcx>(query: Q, qcx: Qcx, span: Span, key: Q::Key) -> Q::Value +where + Q: QueryConfig<Qcx>, + Qcx: QueryContext, +{ + debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled()); + + ensure_sufficient_stack(|| try_execute_query::<Q, Qcx, false>(query, qcx, span, key, None).0) +} + +#[inline(always)] +pub fn get_query_incr<Q, Qcx>( query: Q, qcx: Qcx, span: Span, @@ -810,6 +822,8 @@ where Q: QueryConfig<Qcx>, Qcx: QueryContext, { + debug_assert!(qcx.dep_context().dep_graph().is_fully_enabled()); + let dep_node = if let QueryMode::Ensure { check_cache } = mode { let (must_run, dep_node) = ensure_must_run(query, qcx, &key, check_cache); if !must_run { @@ -820,8 +834,9 @@ where None }; - let (result, dep_node_index) = - ensure_sufficient_stack(|| try_execute_query(query, qcx, span, key, dep_node)); + let (result, dep_node_index) = ensure_sufficient_stack(|| { + try_execute_query::<_, _, true>(query, qcx, span, key, dep_node) + }); if let Some(dep_node_index) = dep_node_index { qcx.dep_context().dep_graph().read_index(dep_node_index) } @@ -846,5 +861,7 @@ pub fn force_query<Q, Qcx>( debug_assert!(!query.anon()); - ensure_sufficient_stack(|| try_execute_query(query, qcx, DUMMY_SP, key, Some(dep_node))); + ensure_sufficient_stack(|| { + try_execute_query::<_, _, true>(query, qcx, DUMMY_SP, key, Some(dep_node)) + }); } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 2438b3a38ed..08b73ebb694 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -9,12 +9,9 @@ use crate::def_collector::collect_definitions; use crate::imports::{Import, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::Namespace::{self, MacroNS, TypeNS, ValueNS}; -use crate::{ - errors, Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot, -}; -use crate::{ - MacroData, NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError, -}; +use crate::{errors, BindingKey, MacroData}; +use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot}; +use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError}; use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError}; use rustc_ast::visit::{self, AssocCtxt, Visitor}; @@ -72,7 +69,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { T: ToNameBinding<'a>, { let binding = def.to_name_binding(self.arenas); - let key = self.new_key(ident, ns); + let key = self.new_disambiguated_key(ident, ns); if let Err(old_binding) = self.try_define(parent, key, binding) { self.report_conflict(parent, ident, ns, old_binding, &binding); } @@ -379,7 +376,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { ImportKind::Single { target, type_ns_only, .. } => { self.r.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let key = this.new_key(target, ns); + let key = BindingKey::new(target, ns); let mut resolution = this.resolution(current_module, key).borrow_mut(); resolution.add_single_import(import); } diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 6675b8ed59b..ed0a792d387 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -28,10 +28,10 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, SyntaxContext}; use thin_vec::ThinVec; -use crate::errors as errs; use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; use crate::path_names_to_string; +use crate::{errors as errs, BindingKey}; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize}; use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError}; @@ -550,7 +550,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let sm = self.tcx.sess.source_map(); let def_id = match outer_res { - Res::SelfTyParam { .. } | Res::SelfCtor(_) => { + Res::SelfTyParam { .. } => { err.span_label(span, "can't use `Self` here"); return err; } @@ -1832,7 +1832,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } (msg, None) } else if ident.name == kw::SelfUpper { - ("`Self` is only available in impls, traits, and type definitions".to_string(), None) + // As mentioned above, `opt_ns` being `None` indicates a module path in import. + // We can use this to improve a confusing error for, e.g. `use Self::Variant` in an + // impl + if opt_ns.is_none() { + ("`Self` cannot be used in imports".to_string(), None) + } else { + ( + "`Self` is only available in impls, traits, and type definitions".to_string(), + None, + ) + } } else if ident.name.as_str().chars().next().map_or(false, |c| c.is_ascii_uppercase()) { // Check whether the name refers to an item in the value namespace. let binding = if let Some(ribs) = ribs { @@ -2081,7 +2091,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } let resolutions = self.resolutions(crate_module).borrow(); - let resolution = resolutions.get(&self.new_key(ident, MacroNS))?; + let binding_key = BindingKey::new(ident, MacroNS); + let resolution = resolutions.get(&binding_key)?; let binding = resolution.borrow().binding()?; if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() { let module_name = crate_module.kind.name().unwrap(); diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index 87067189a77..7393bdb388a 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -199,7 +199,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { let tcx = self.r.tcx; self.changed |= self.import_effective_visibilities.update( binding, - nominal_vis, + Some(nominal_vis), || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_import(binding)), inherited_eff_vis, parent_id.level(), @@ -213,7 +213,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { let tcx = self.r.tcx; self.changed |= self.def_effective_visibilities.update( def_id, - nominal_vis, + Some(nominal_vis), || cheap_private_vis.unwrap_or_else(|| self.r.private_vis_def(def_id)), inherited_eff_vis, parent_id.level(), diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 755acdd81fe..945c7ce3a9b 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -18,6 +18,7 @@ use crate::late::{ ConstantHasGenerics, HasGenericParams, NoConstantGenericsReason, PathSource, Rib, RibKind, }; use crate::macros::{sub_namespace_match, MacroRulesScope}; +use crate::BindingKey; use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; use crate::{Import, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res}; @@ -865,7 +866,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } }; - let key = self.new_key(ident, ns); + let key = BindingKey::new(ident, ns); let resolution = self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. @@ -1174,10 +1175,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return Res::Err; } } - Res::Def(DefKind::TyParam, _) - | Res::SelfTyParam { .. } - | Res::SelfTyAlias { .. } - | Res::SelfCtor(_) => { + Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => { for rib in ribs { let has_generic_params: HasGenericParams = match rib.kind { RibKind::Normal diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 9e4429507b1..7c4c05d4b94 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -405,17 +405,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { t } - // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed resolution, - // also mark such failed imports as used to avoid duplicate diagnostics. - fn import_dummy_binding(&mut self, import: &'a Import<'a>) { + // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed + // or indeterminate resolution, also mark such failed imports as used to avoid duplicate diagnostics. + fn import_dummy_binding(&mut self, import: &'a Import<'a>, is_indeterminate: bool) { if let ImportKind::Single { target, ref target_bindings, .. } = import.kind { - if target_bindings.iter().any(|binding| binding.get().is_some()) { + if !(is_indeterminate || target_bindings.iter().all(|binding| binding.get().is_none())) + { return; // Has resolution, do not create the dummy binding } let dummy_binding = self.dummy_binding; let dummy_binding = self.import(dummy_binding, import); self.per_ns(|this, ns| { - let key = this.new_key(target, ns); + let key = BindingKey::new(target, ns); let _ = this.try_define(import.parent_scope.module, key, dummy_binding); }); self.record_use(target, dummy_binding, false); @@ -474,7 +475,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // If this import is unresolved then create a dummy import // resolution for it so that later resolve stages won't complain. - self.import_dummy_binding(import); + self.import_dummy_binding(import, is_indeterminate); if let Some(err) = unresolved_import_error { if let ImportKind::Single { source, ref source_bindings, .. } = import.kind { @@ -712,7 +713,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .span_label(import.span, "cannot be imported directly") .emit(); } - let key = this.new_key(target, ns); + let key = BindingKey::new(target, ns); this.update_resolution(parent, key, |_, resolution| { resolution.single_imports.remove(&Interned::new_unchecked(import)); }); diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 44e277c99b9..a1077615d95 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -6,6 +6,7 @@ //! If you wonder why there's no `early.rs`, that's because it's split into three files - //! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`. +use crate::BindingKey; use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding}; use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult}; use crate::{ResolutionError, Resolver, Segment, UseError}; @@ -2967,7 +2968,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // If there is a TraitRef in scope for an impl, then the method must be in the trait. let Some((module, _)) = &self.current_trait_ref else { return; }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); - let key = self.r.new_key(ident, ns); + let key = BindingKey::new(ident, ns); let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding); debug!(?binding); if binding.is_none() { @@ -2978,7 +2979,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { TypeNS => ValueNS, _ => ns, }; - let key = self.r.new_key(ident, ns); + let key = BindingKey::new(ident, ns); binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding); debug!(?binding); } @@ -3543,10 +3544,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { // // Similar thing, for types, happens in `report_errors` above. let report_errors_for_call = |this: &mut Self, parent_err: Spanned<ResolutionError<'a>>| { - if !source.is_call() { - return Some(parent_err); - } - // Before we start looking for candidates, we have to get our hands // on the type user is trying to perform invocation on; basically: // we're transforming `HashMap::new` into just `HashMap`. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c12dc2f5d92..3cdc3f0ecf8 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -47,6 +47,7 @@ use rustc_index::IndexVec; use rustc_metadata::creader::{CStore, CrateLoader}; use rustc_middle::metadata::ModChild; use rustc_middle::middle::privacy::EffectiveVisibilities; +use rustc_middle::query::Providers; use rustc_middle::span_bug; use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt}; use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs}; @@ -84,6 +85,7 @@ pub mod rustdoc; fluent_messages! { "../messages.ftl" } +#[derive(Debug)] enum Weak { Yes, No, @@ -468,6 +470,13 @@ struct BindingKey { disambiguator: u32, } +impl BindingKey { + fn new(ident: Ident, ns: Namespace) -> Self { + let ident = ident.normalize_to_macros_2_0(); + BindingKey { ident, ns, disambiguator: 0 } + } +} + type Resolutions<'a> = RefCell<FxIndexMap<BindingKey, &'a RefCell<NameResolution<'a>>>>; /// One node in the tree of modules. @@ -942,6 +951,7 @@ pub struct Resolver<'a, 'tcx> { empty_module: Module<'a>, module_map: FxHashMap<DefId, Module<'a>>, binding_parent_modules: FxHashMap<Interned<'a, NameBinding<'a>>, Module<'a>>, + underscore_disambiguator: u32, /// Maps glob imports to the names of items actually imported. @@ -1594,7 +1604,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { import_ids } - fn new_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey { + fn new_disambiguated_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey { let ident = ident.normalize_to_macros_2_0(); let disambiguator = if ident.name == kw::Underscore { self.underscore_disambiguator += 1; @@ -2026,6 +2036,6 @@ impl Finalize { } } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { providers.registered_tools = macros::registered_tools; } diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 6b559cb5b2f..0ffc537eee0 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -1,4 +1,4 @@ -use crate::leb128::{self, largest_max_leb128_len}; +use crate::leb128; use crate::serialize::{Decodable, Decoder, Encodable, Encoder}; use std::fs::File; use std::io::{self, Write}; @@ -14,6 +14,9 @@ use std::ptr; pub type FileEncodeResult = Result<usize, io::Error>; +/// The size of the buffer in `FileEncoder`. +const BUF_SIZE: usize = 8192; + /// `FileEncoder` encodes data to file via fixed-size buffer. /// /// There used to be a `MemEncoder` type that encoded all the data into a @@ -35,26 +38,12 @@ pub struct FileEncoder { impl FileEncoder { pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> { - const DEFAULT_BUF_SIZE: usize = 8192; - FileEncoder::with_capacity(path, DEFAULT_BUF_SIZE) - } - - pub fn with_capacity<P: AsRef<Path>>(path: P, capacity: usize) -> io::Result<Self> { - // Require capacity at least as large as the largest LEB128 encoding - // here, so that we don't have to check or handle this on every write. - assert!(capacity >= largest_max_leb128_len()); - - // Require capacity small enough such that some capacity checks can be - // done using guaranteed non-overflowing add rather than sub, which - // shaves an instruction off those code paths (on x86 at least). - assert!(capacity <= usize::MAX - largest_max_leb128_len()); - // Create the file for reading and writing, because some encoders do both // (e.g. the metadata encoder when -Zmeta-stats is enabled) let file = File::options().read(true).write(true).create(true).truncate(true).open(path)?; Ok(FileEncoder { - buf: Box::new_uninit_slice(capacity), + buf: Box::new_uninit_slice(BUF_SIZE), buffered: 0, flushed: 0, file, @@ -160,18 +149,10 @@ impl FileEncoder { } #[inline] - fn capacity(&self) -> usize { - self.buf.len() - } - - #[inline] fn write_one(&mut self, value: u8) { - // We ensure this during `FileEncoder` construction. - debug_assert!(self.capacity() >= 1); - let mut buffered = self.buffered; - if std::intrinsics::unlikely(buffered >= self.capacity()) { + if std::intrinsics::unlikely(buffered + 1 > BUF_SIZE) { self.flush(); buffered = 0; } @@ -187,13 +168,12 @@ impl FileEncoder { #[inline] fn write_all(&mut self, buf: &[u8]) { - let capacity = self.capacity(); let buf_len = buf.len(); - if std::intrinsics::likely(buf_len <= capacity) { + if std::intrinsics::likely(buf_len <= BUF_SIZE) { let mut buffered = self.buffered; - if std::intrinsics::unlikely(buf_len > capacity - buffered) { + if std::intrinsics::unlikely(buffered + buf_len > BUF_SIZE) { self.flush(); buffered = 0; } @@ -271,13 +251,11 @@ macro_rules! write_leb128 { fn $this_fn(&mut self, v: $int_ty) { const MAX_ENCODED_LEN: usize = $crate::leb128::max_leb128_len::<$int_ty>(); - // We ensure this during `FileEncoder` construction. - debug_assert!(self.capacity() >= MAX_ENCODED_LEN); - let mut buffered = self.buffered; - // This can't overflow. See assertion in `FileEncoder::with_capacity`. - if std::intrinsics::unlikely(buffered + MAX_ENCODED_LEN > self.capacity()) { + // This can't overflow because BUF_SIZE and MAX_ENCODED_LEN are both + // quite small. + if std::intrinsics::unlikely(buffered + MAX_ENCODED_LEN > BUF_SIZE) { self.flush(); buffered = 0; } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index aa3cb03bad8..a328447aca9 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -421,7 +421,7 @@ pub enum TrimmedDefPaths { GoodPath, } -#[derive(Clone, Hash)] +#[derive(Clone, Hash, Debug)] pub enum ResolveDocLinks { /// Do not resolve doc links. None, @@ -1060,6 +1060,9 @@ fn default_configuration(sess: &Session) -> CrateConfig { if sess.opts.debug_assertions { ret.insert((sym::debug_assertions, None)); } + if sess.overflow_checks() { + ret.insert((sym::overflow_checks, None)); + } // JUSTIFICATION: before wrapper fn is available #[allow(rustc::bad_opt_access)] if sess.opts.crate_types.contains(&CrateType::ProcMacro) { @@ -1209,6 +1212,7 @@ impl CrateCheckConfig { sym::windows, sym::proc_macro, sym::debug_assertions, + sym::overflow_checks, sym::target_thread_local, ] { self.expecteds.entry(name).or_insert_with(no_values); @@ -1315,7 +1319,7 @@ pub(super) fn build_target_config( let (target, target_warnings) = target_result.unwrap_or_else(|e| { early_error( opts.error_format, - &format!( + format!( "Error loading target specification: {}. \ Run `rustc --print target-list` for a list of built-in targets", e @@ -1323,15 +1327,14 @@ pub(super) fn build_target_config( ) }); for warning in target_warnings.warning_messages() { - early_warn(opts.error_format, &warning) + early_warn(opts.error_format, warning) } if !matches!(target.pointer_width, 16 | 32 | 64) { early_error( opts.error_format, - &format!( - "target specification was invalid: \ - unrecognized target-pointer-width {}", + format!( + "target specification was invalid: unrecognized target-pointer-width {}", target.pointer_width ), ) @@ -1595,7 +1598,7 @@ pub fn get_cmd_lint_options( let lint_cap = matches.opt_str("cap-lints").map(|cap| { lint::Level::from_str(&cap) - .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`"))) + .unwrap_or_else(|| early_error(error_format, format!("unknown lint level: `{cap}`"))) }); (lint_opts, describe_lints, lint_cap) @@ -1612,7 +1615,7 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig { Some(arg) => early_error( ErrorOutputType::default(), - &format!( + format!( "argument for `--color` must be auto, \ always or never (instead was `{arg}`)" ), @@ -1687,7 +1690,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig { "future-incompat" => json_future_incompat = true, s => early_error( ErrorOutputType::default(), - &format!("unknown `--json` option `{s}`"), + format!("unknown `--json` option `{s}`"), ), } } @@ -1725,7 +1728,7 @@ pub fn parse_error_format( Some(arg) => early_error( ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)), - &format!( + format!( "argument for `--error-format` must be `human`, `json` or \ `short` (instead was `{arg}`)" ), @@ -1759,7 +1762,7 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition { Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| { early_error( ErrorOutputType::default(), - &format!( + format!( "argument for `--edition` must be one of: \ {EDITION_NAME_LIST}. (instead was `{arg}`)" ), @@ -1778,7 +1781,7 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition { } else { format!("edition {edition} is unstable and only available with -Z unstable-options") }; - early_error(ErrorOutputType::default(), &msg) + early_error(ErrorOutputType::default(), msg) } edition @@ -1823,7 +1826,7 @@ fn parse_output_types( let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| { early_error( error_format, - &format!( + format!( "unknown emission type: `{shorthand}` - expected one of: {display}", display = OutputType::shorthands_display(), ), @@ -1862,7 +1865,7 @@ fn should_override_cgus_and_disable_thinlto( for ot in &incompatible { early_warn( error_format, - &format!( + format!( "`--emit={ot}` with `-o` incompatible with \ `-C codegen-units=N` for N > 1", ), @@ -1966,7 +1969,7 @@ fn collect_print_requests( let prints = prints.join(", "); early_error( error_format, - &format!("unknown print request `{req}`. Valid print requests are: {prints}"), + format!("unknown print request `{req}`. Valid print requests are: {prints}"), ); } } @@ -1983,7 +1986,7 @@ pub fn parse_target_triple( Some(target) if target.ends_with(".json") => { let path = Path::new(&target); TargetTriple::from_path(path).unwrap_or_else(|_| { - early_error(error_format, &format!("target file {path:?} does not exist")) + early_error(error_format, format!("target file {path:?} does not exist")) }) } Some(target) => TargetTriple::TargetTriple(target), @@ -2024,7 +2027,7 @@ fn parse_opt_level( arg => { early_error( error_format, - &format!( + format!( "optimization level needs to be \ between 0-3, s or z (instead was `{arg}`)" ), @@ -2055,7 +2058,7 @@ pub(crate) fn parse_assert_incr_state( Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded), Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded), Some(s) => { - early_error(error_format, &format!("unexpected incremental state assertion value: {s}")) + early_error(error_format, format!("unexpected incremental state assertion value: {s}")) } None => None, } @@ -2082,13 +2085,13 @@ fn parse_native_lib_kind( } else { ", the `-Z unstable-options` flag must also be passed to use it" }; - early_error(error_format, &format!("library kind `link-arg` is unstable{why}")) + early_error(error_format, format!("library kind `link-arg` is unstable{why}")) } NativeLibKind::LinkArg } _ => early_error( error_format, - &format!( + format!( "unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg" ), ), @@ -2123,16 +2126,13 @@ fn parse_native_lib_modifiers( } else { ", the `-Z unstable-options` flag must also be passed to use it" }; - early_error( - error_format, - &format!("linking modifier `{modifier}` is unstable{why}"), - ) + early_error(error_format, format!("linking modifier `{modifier}` is unstable{why}")) } }; let assign_modifier = |dst: &mut Option<bool>| { if dst.is_some() { let msg = format!("multiple `{modifier}` modifiers in a single `-l` option"); - early_error(error_format, &msg) + early_error(error_format, msg) } else { *dst = Some(value); } @@ -2169,7 +2169,7 @@ fn parse_native_lib_modifiers( // string, like `modifiers = ""`. _ => early_error( error_format, - &format!( + format!( "unknown linking modifier `{modifier}`, expected one \ of: bundle, verbatim, whole-archive, as-needed" ), @@ -2299,7 +2299,7 @@ pub fn parse_externs( } "nounused" => nounused_dep = true, "force" => force = true, - _ => early_error(error_format, &format!("unknown --extern option `{opt}`")), + _ => early_error(error_format, format!("unknown --extern option `{opt}`")), } } } @@ -2365,7 +2365,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { let unparsed_crate_types = matches.opt_strs("crate-type"); let crate_types = parse_crate_types_from_list(unparsed_crate_types) - .unwrap_or_else(|e| early_error(error_format, &e)); + .unwrap_or_else(|e| early_error(error_format, e)); let mut unstable_opts = UnstableOptions::build(matches, error_format); let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format); @@ -2593,7 +2593,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { }; let working_dir = std::env::current_dir().unwrap_or_else(|e| { - early_error(error_format, &format!("Current directory is invalid: {e}")); + early_error(error_format, format!("Current directory is invalid: {e}")); }); let remap = FilePathMapping::new(remap_path_prefix.clone()); @@ -2665,7 +2665,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio "mir-cfg" => MirCFG, name => early_error( efmt, - &format!( + format!( "argument to `unpretty` must be one of `normal`, `identified`, \ `expanded`, `expanded,identified`, `expanded,hygiene`, \ `ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \ @@ -2743,7 +2743,7 @@ pub mod nightly_options { if opt.name != "Z" && !has_z_unstable_option { early_error( ErrorOutputType::default(), - &format!( + format!( "the `-Z unstable-options` flag must also be passed to enable \ the flag `{}`", opt.name @@ -2756,11 +2756,10 @@ pub mod nightly_options { match opt.stability { OptionStability::Unstable => { let msg = format!( - "the option `{}` is only accepted on the \ - nightly compiler", + "the option `{}` is only accepted on the nightly compiler", opt.name ); - early_error(ErrorOutputType::default(), &msg); + early_error(ErrorOutputType::default(), msg); } OptionStability::Stable => {} } diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs index dd1721801f3..dc475e8c6d5 100644 --- a/compiler/rustc_session/src/cstore.rs +++ b/compiler/rustc_session/src/cstore.rs @@ -6,7 +6,8 @@ use crate::search_paths::PathKind; use crate::utils::NativeLibKind; use crate::Session; use rustc_ast as ast; -use rustc_data_structures::sync::{self, AppendOnlyIndexVec, MetadataRef, RwLock}; +use rustc_data_structures::owned_slice::OwnedSlice; +use rustc_data_structures::sync::{self, AppendOnlyIndexVec, RwLock}; use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE}; use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions}; use rustc_span::hygiene::{ExpnHash, ExpnId}; @@ -203,11 +204,11 @@ pub enum ExternCrateSource { /// metadata in library -- this trait just serves to decouple rustc_metadata from /// the archive reader, which depends on LLVM. pub trait MetadataLoader: std::fmt::Debug { - fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>; - fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>; + fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>; + fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>; } -pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync; +pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync; /// A store of Rust crates, through which their metadata can be accessed. /// @@ -252,7 +253,7 @@ pub trait CrateStore: std::fmt::Debug { fn import_source_files(&self, sess: &Session, cnum: CrateNum); } -pub type CrateStoreDyn = dyn CrateStore + sync::Sync + sync::Send; +pub type CrateStoreDyn = dyn CrateStore + sync::DynSync + sync::DynSend; pub struct Untracked { pub cstore: RwLock<Box<CrateStoreDyn>>, diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 5976b9aa3e7..2c4c4a7a6ce 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -329,21 +329,21 @@ fn build_options<O: Default>( match value { None => early_error( error_format, - &format!( + format!( "{0} option `{1}` requires {2} ({3} {1}=<value>)", outputname, key, type_desc, prefix ), ), Some(value) => early_error( error_format, - &format!( + format!( "incorrect value `{value}` for {outputname} option `{key}` - {type_desc} was expected" ), ), } } } - None => early_error(error_format, &format!("unknown {outputname} option: `{key}`")), + None => early_error(error_format, format!("unknown {outputname} option: `{key}`")), } } return op; diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 5cc9c62617d..7b396dde91b 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -289,7 +289,7 @@ impl ParseSess { lint: &'static Lint, span: impl Into<MultiSpan>, node_id: NodeId, - msg: &str, + msg: impl Into<DiagnosticMessage>, ) { self.buffered_lints.with_lock(|buffered_lints| { buffered_lints.push(BufferedEarlyLint { @@ -307,7 +307,7 @@ impl ParseSess { lint: &'static Lint, span: impl Into<MultiSpan>, node_id: NodeId, - msg: &str, + msg: impl Into<DiagnosticMessage>, diagnostic: BuiltinLintDiagnostics, ) { self.buffered_lints.with_lock(|buffered_lints| { diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index a988d7f28e6..4f593083b6f 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -211,6 +211,9 @@ pub struct Session { /// Set of enabled features for the current target, including unstable ones. pub unstable_target_features: FxIndexSet<Symbol>, + + /// The version of the rustc process, possibly including a commit hash and description. + pub cfg_version: &'static str, } pub struct PerfStats { @@ -490,20 +493,6 @@ impl Session { } #[rustc_lint_diagnostics] #[track_caller] - pub fn span_err_or_warn<S: Into<MultiSpan>>( - &self, - is_warning: bool, - sp: S, - msg: impl Into<DiagnosticMessage>, - ) { - if is_warning { - self.span_warn(sp, msg); - } else { - self.span_err(sp, msg); - } - } - #[rustc_lint_diagnostics] - #[track_caller] pub fn span_err<S: Into<MultiSpan>>( &self, sp: S, @@ -1380,6 +1369,7 @@ pub fn build_session( driver_lint_caps: FxHashMap<lint::LintId, lint::Level>, file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>, target_override: Option<Target>, + cfg_version: &'static str, ) -> Session { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed @@ -1400,10 +1390,10 @@ pub fn build_session( let target_cfg = config::build_target_config(&sopts, target_override, &sysroot); let host_triple = TargetTriple::from_triple(config::host_triple()); let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| { - early_error(sopts.error_format, &format!("Error loading host specification: {e}")) + early_error(sopts.error_format, format!("Error loading host specification: {e}")) }); for warning in target_warnings.warning_messages() { - early_warn(sopts.error_format, &warning) + early_warn(sopts.error_format, warning) } let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader)); @@ -1445,7 +1435,7 @@ pub fn build_session( match profiler { Ok(profiler) => Some(Arc::new(profiler)), Err(e) => { - early_warn(sopts.error_format, &format!("failed to create profiler: {e}")); + early_warn(sopts.error_format, format!("failed to create profiler: {e}")); None } } @@ -1524,6 +1514,7 @@ pub fn build_session( asm_arch, target_features: Default::default(), unstable_target_features: Default::default(), + cfg_version, }; validate_commandline_args_with_session_available(&sess); @@ -1741,18 +1732,22 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] -pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed { +#[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"] +pub fn early_error_no_abort( + output: config::ErrorOutputType, + msg: impl Into<DiagnosticMessage>, +) -> ErrorGuaranteed { early_error_handler(output).struct_err(msg).emit() } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] -pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! { +pub fn early_error(output: config::ErrorOutputType, msg: impl Into<DiagnosticMessage>) -> ! { early_error_handler(output).struct_fatal(msg).emit() } #[allow(rustc::untranslatable_diagnostic)] #[allow(rustc::diagnostic_outside_of_impl)] -pub fn early_warn(output: config::ErrorOutputType, msg: &str) { +pub fn early_warn(output: config::ErrorOutputType, msg: impl Into<DiagnosticMessage>) { early_error_handler(output).struct_warn(msg).emit() } diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs index 8c58b52a5dc..f65a6aa4fb2 100644 --- a/compiler/rustc_span/src/def_id.rs +++ b/compiler/rustc_span/src/def_id.rs @@ -146,7 +146,12 @@ pub struct StableCrateId(pub(crate) Hash64); impl StableCrateId { /// Computes the stable ID for a crate with the given name and /// `-Cmetadata` arguments. - pub fn new(crate_name: Symbol, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId { + pub fn new( + crate_name: Symbol, + is_exe: bool, + mut metadata: Vec<String>, + cfg_version: &'static str, + ) -> StableCrateId { let mut hasher = StableHasher::new(); // We must hash the string text of the crate name, not the id, as the id is not stable // across builds. @@ -180,7 +185,7 @@ impl StableCrateId { if let Some(val) = std::env::var_os("RUSTC_FORCE_RUSTC_VERSION") { hasher.write(val.to_string_lossy().into_owned().as_bytes()) } else { - hasher.write(option_env!("CFG_VERSION").unwrap_or("unknown version").as_bytes()); + hasher.write(cfg_version.as_bytes()) } StableCrateId(hasher.finish()) diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 7bbab34c69a..8d70aa47f78 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -20,6 +20,7 @@ #![feature(min_specialization)] #![feature(rustc_attrs)] #![feature(let_chains)] +#![feature(round_char_boundary)] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] @@ -1256,29 +1257,6 @@ impl SourceFileHash { } } -#[derive(HashStable_Generic)] -#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)] -pub enum DebuggerVisualizerType { - Natvis, - GdbPrettyPrinter, -} - -/// A single debugger visualizer file. -#[derive(HashStable_Generic)] -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)] -pub struct DebuggerVisualizerFile { - /// The complete debugger visualizer source. - pub src: Lrc<[u8]>, - /// Indicates which visualizer type this targets. - pub visualizer_type: DebuggerVisualizerType, -} - -impl DebuggerVisualizerFile { - pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType) -> Self { - DebuggerVisualizerFile { src, visualizer_type } - } -} - #[derive(Clone)] pub enum SourceFileLines { /// The source file lines, in decoded (random-access) form. diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 1294a8b8e6b..11ea5fe4ddf 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -14,7 +14,9 @@ pub use crate::*; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::{Hash128, Hash64, StableHasher}; -use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock}; +use rustc_data_structures::sync::{ + AtomicU32, IntoDynSyncSend, Lrc, MappedReadGuard, ReadGuard, RwLock, +}; use std::cmp; use std::hash::Hash; use std::path::{self, Path, PathBuf}; @@ -176,7 +178,7 @@ pub struct SourceMap { used_address_space: AtomicU32, files: RwLock<SourceMapFiles>, - file_loader: Box<dyn FileLoader + Sync + Send>, + file_loader: IntoDynSyncSend<Box<dyn FileLoader + Sync + Send>>, // This is used to apply the file path remapping as specified via // `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`. path_mapping: FilePathMapping, @@ -202,7 +204,7 @@ impl SourceMap { SourceMap { used_address_space: AtomicU32::new(0), files: Default::default(), - file_loader, + file_loader: IntoDynSyncSend(file_loader), path_mapping, hash_kind, } @@ -1017,36 +1019,19 @@ impl SourceMap { let src = local_begin.sf.external_src.borrow(); - // We need to extend the snippet to the end of the src rather than to end_index so when - // searching forwards for boundaries we've got somewhere to search. - let snippet = if let Some(ref src) = local_begin.sf.src { - &src[start_index..] + let snippet = if let Some(src) = &local_begin.sf.src { + src } else if let Some(src) = src.get_source() { - &src[start_index..] + src } else { return 1; }; - debug!("snippet=`{:?}`", snippet); - let mut target = if forwards { end_index + 1 } else { end_index - 1 }; - debug!("initial target=`{:?}`", target); - - while !snippet.is_char_boundary(target - start_index) && target < source_len { - target = if forwards { - target + 1 - } else { - match target.checked_sub(1) { - Some(target) => target, - None => { - break; - } - } - }; - debug!("target=`{:?}`", target); + if forwards { + (snippet.ceil_char_boundary(end_index + 1) - end_index) as u32 + } else { + (end_index - snippet.floor_char_boundary(end_index - 1)) as u32 } - debug!("final target=`{:?}`", target); - - if forwards { (target - end_index) as u32 } else { (end_index - target) as u32 } } pub fn get_source_file(&self, filename: &FileName) -> Option<Lrc<SourceFile>> { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 60efcb768cb..874d578fe1d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -164,6 +164,7 @@ symbols! { Capture, Center, Clone, + ConstParamTy, Context, Continue, Copy, @@ -463,6 +464,7 @@ symbols! { cfg_doctest, cfg_eval, cfg_hide, + cfg_overflow_checks, cfg_panic, cfg_sanitize, cfg_target_abi, @@ -1065,6 +1067,7 @@ symbols! { or_patterns, other, out, + overflow_checks, overlapping_marker_traits, owned_box, packed, @@ -1581,6 +1584,7 @@ symbols! { unrestricted_attribute_tokens, unsafe_block_in_unsafe_fn, unsafe_cell, + unsafe_cell_from_mut, unsafe_no_drop_flag, unsafe_pin_internals, unsize, diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index c97406868b6..692542da78e 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -107,7 +107,7 @@ use rustc_hir::def_id::{CrateNum, LOCAL_CRATE}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; use rustc_middle::mir::mono::{InstantiationMode, MonoItem}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Instance, TyCtxt}; use rustc_session::config::SymbolManglingVersion; diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs index c281aa7e83a..51d508a580b 100644 --- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs +++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs @@ -673,6 +673,14 @@ fn encode_ty<'tcx>( typeid.push_str(&s); } + // Type parameters + ty::Param(..) => { + // u5param as vendor extended type + let mut s = String::from("u5param"); + compress(dict, DictKey::Ty(ty, TyQ::None), &mut s); + typeid.push_str(&s); + } + // Unexpected types ty::Bound(..) | ty::Error(..) @@ -680,7 +688,6 @@ fn encode_ty<'tcx>( | ty::GeneratorWitnessMIR(..) | ty::Infer(..) | ty::Alias(..) - | ty::Param(..) | ty::Placeholder(..) => { bug!("encode_ty: unexpected `{:?}`", ty.kind()); } @@ -689,6 +696,41 @@ fn encode_ty<'tcx>( typeid } +/// Transforms predicates for being encoded and used in the substitution dictionary. +fn transform_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: &List<ty::PolyExistentialPredicate<'tcx>>, + _options: EncodeTyOptions, +) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> { + let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> = predicates + .iter() + .map(|predicate| match predicate.skip_binder() { + ty::ExistentialPredicate::Trait(trait_ref) => { + let trait_ref = ty::TraitRef::identity(tcx, trait_ref.def_id); + ty::Binder::dummy(ty::ExistentialPredicate::Trait( + ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref), + )) + } + _ => predicate, + }) + .collect(); + tcx.mk_poly_existential_predicates(&predicates) +} + +/// Transforms substs for being encoded and used in the substitution dictionary. +fn transform_substs<'tcx>( + tcx: TyCtxt<'tcx>, + substs: SubstsRef<'tcx>, + options: TransformTyOptions, +) -> SubstsRef<'tcx> { + let substs = substs.iter().map(|subst| match subst.unpack() { + GenericArgKind::Type(ty) if ty.is_c_void(tcx) => tcx.mk_unit().into(), + GenericArgKind::Type(ty) => transform_ty(tcx, ty, options).into(), + _ => subst, + }); + tcx.mk_substs_from_iter(substs) +} + // Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all // c_void types into unit types unconditionally, generalizes pointers if // TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if @@ -697,7 +739,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio let mut ty = ty; match ty.kind() { - ty::Float(..) | ty::Char | ty::Str | ty::Never | ty::Foreign(..) | ty::Dynamic(..) => {} + ty::Float(..) | ty::Char | ty::Str | ty::Never | ty::Foreign(..) => {} ty::Bool => { if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) { @@ -870,6 +912,14 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio } } + ty::Dynamic(predicates, _region, kind) => { + ty = tcx.mk_dynamic( + transform_predicates(tcx, predicates, options), + tcx.lifetimes.re_erased, + *kind, + ); + } + ty::Bound(..) | ty::Error(..) | ty::GeneratorWitness(..) @@ -885,20 +935,6 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio ty } -/// Transforms substs for being encoded and used in the substitution dictionary. -fn transform_substs<'tcx>( - tcx: TyCtxt<'tcx>, - substs: SubstsRef<'tcx>, - options: TransformTyOptions, -) -> SubstsRef<'tcx> { - let substs = substs.iter().map(|subst| match subst.unpack() { - GenericArgKind::Type(ty) if ty.is_c_void(tcx) => tcx.mk_unit().into(), - GenericArgKind::Type(ty) => transform_ty(tcx, ty, options).into(), - _ => subst, - }); - tcx.mk_substs_from_iter(substs) -} - /// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor /// extended type qualifiers and types for Rust types that are not used at the FFI boundary. #[instrument(level = "trace", skip(tcx))] diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 705966f5237..e60b8e78e5d 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -882,8 +882,8 @@ impl InlineAsmClobberAbi { _ => Err(&["C", "system", "efiapi"]), }, InlineAsmArch::LoongArch64 => match name { - "C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::LoongArch), - _ => Err(&["C", "system", "efiapi"]), + "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch), + _ => Err(&["C", "system"]), }, _ => Err(&[]), } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 25cc82f01d5..d14e6244f7d 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -506,10 +506,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { | ty::Param(_) | ty::Placeholder(..) | ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) + | ty::Alias(ty::Inherent, _) | ty::Error(_) => return, ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) | ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"), - ty::Alias(_, alias_ty) => alias_ty, + // Excluding IATs here as they don't have meaningful item bounds. + ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty, }; for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs) diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 20ce2d9416e..d3228074421 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -124,10 +124,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { }; if !assoc_def.item.defaultness(tcx).has_value() { - tcx.sess.delay_span_bug( + let guar = tcx.sess.delay_span_bug( tcx.def_span(assoc_def.item.def_id), "missing value for assoc item in impl", ); + let error_term = match assoc_def.item.kind { + ty::AssocKind::Const => tcx + .const_error( + tcx.type_of(goal.predicate.def_id()) + .subst(tcx, goal.predicate.projection_ty.substs), + guar, + ) + .into(), + ty::AssocKind::Type => tcx.ty_error(guar).into(), + ty::AssocKind::Fn => unreachable!(), + }; + ecx.eq(goal.param_env, goal.predicate.term, error_term) + .expect("expected goal term to be fully unconstrained"); + return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes); } // Getting the right substitutions here is complex, e.g. given: diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs index 6b080a132f3..183c2401fc3 100644 --- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -801,7 +801,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { span: tcx.def_span(unevaluated.def), unevaluated: unevaluated, }); - Err(ErrorHandled::Reported(reported)) + Err(ErrorHandled::Reported(reported.into())) } Err(err) => Err(err), } diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs index 9d99d30d45c..bd1ea43a78e 100644 --- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -79,7 +79,7 @@ pub fn is_const_evaluatable<'tcx>( "Missing value for constant, but no error reported?", ))) } - Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), + Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())), Ok(_) => Ok(()), } } @@ -147,7 +147,7 @@ pub fn is_const_evaluatable<'tcx>( Err(err) } - Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)), + Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())), Ok(_) => Ok(()), } } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 98365223923..f5f2fe54217 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -797,9 +797,17 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_label(span, explanation); } - if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() && - Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { - self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty); + if let ObligationCauseCode::Coercion { source, target } = + *obligation.cause.code().peel_derives() + { + if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() { + self.suggest_borrowing_for_object_cast( + &mut err, + &root_obligation, + source, + target, + ); + } } let UnsatisfiedConst(unsatisfied_const) = self @@ -1510,7 +1518,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::BindingObligation(_, _) | ObligationCauseCode::ExprItemObligation(..) | ObligationCauseCode::ExprBindingObligation(..) - | ObligationCauseCode::ObjectCastObligation(..) + | ObligationCauseCode::Coercion { .. } | ObligationCauseCode::OpaqueType ); 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 88525e1b720..10bd027b684 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 @@ -306,6 +306,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } } } + + // `&[{integral}]` - `FromIterator` needs that. + if let ty::Ref(_, ref_ty, rustc_ast::Mutability::Not) = self_ty.kind() + && let ty::Slice(sty) = ref_ty.kind() + && sty.is_integral() + { + flags.push((sym::_Self, Some("&[{integral}]".to_owned()))); + } }); if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) { 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 53bf38c0a34..ea17f23434b 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1442,8 +1442,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err: &mut Diagnostic, obligation: &PredicateObligation<'tcx>, self_ty: Ty<'tcx>, - object_ty: Ty<'tcx>, + target_ty: Ty<'tcx>, ) { + let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else { return; }; let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; }; let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty); @@ -1458,7 +1459,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_suggestion( obligation.cause.span.shrink_to_lo(), format!( - "consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`" + "consider borrowing the value, since `&{self_ty}` can be coerced into `{target_ty}`" ), "&", Applicability::MaybeIncorrect, @@ -2446,10 +2447,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { && generator_did.is_local() // Try to avoid cycles. && !generator_within_in_progress_typeck + && let Some(generator_info) = self.tcx.mir_generator_witnesses(generator_did) { - let generator_info = &self.tcx.mir_generator_witnesses(generator_did); debug!(?generator_info); - 'find_source: for (variant, source_info) in generator_info.variant_fields.iter().zip(&generator_info.variant_source_info) { @@ -2851,30 +2851,27 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { err.span_note(tcx.def_span(item_def_id), descr); } } - ObligationCauseCode::ObjectCastObligation(concrete_ty, object_ty) => { - let (concrete_ty, concrete_file) = - self.tcx.short_ty_string(self.resolve_vars_if_possible(concrete_ty)); - let (object_ty, object_file) = - self.tcx.short_ty_string(self.resolve_vars_if_possible(object_ty)); + ObligationCauseCode::Coercion { source, target } => { + let (source, source_file) = + self.tcx.short_ty_string(self.resolve_vars_if_possible(source)); + let (target, target_file) = + self.tcx.short_ty_string(self.resolve_vars_if_possible(target)); err.note(with_forced_trimmed_paths!(format!( - "required for the cast from `{concrete_ty}` to the object type `{object_ty}`", + "required for the cast from `{source}` to `{target}`", ))); - if let Some(file) = concrete_file { + if let Some(file) = source_file { err.note(format!( - "the full name for the casted type has been written to '{}'", + "the full name for the source type has been written to '{}'", file.display(), )); } - if let Some(file) = object_file { + if let Some(file) = target_file { err.note(format!( - "the full name for the object type has been written to '{}'", + "the full name for the target type has been written to '{}'", file.display(), )); } } - ObligationCauseCode::Coercion { source: _, target } => { - err.note(format!("required by cast to type `{}`", self.ty_to_string(target))); - } ObligationCauseCode::RepeatElementCopy { is_const_fn } => { err.note( "the `Copy` trait is required because this value will be copied for each element of the array", diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 43196d1e629..2f85c32b575 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -615,7 +615,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> { (Err(ErrorHandled::Reported(reported)), _) | (_, Err(ErrorHandled::Reported(reported))) => ProcessResult::Error( CodeSelectionError(SelectionError::NotConstEvaluatable( - NotConstEvaluatable::Error(reported), + NotConstEvaluatable::Error(reported.into()), )), ), (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 38daca5377a..f265230ff77 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -17,6 +17,7 @@ pub mod query; mod select; mod specialize; mod structural_match; +mod structural_normalize; mod util; mod vtable; pub mod wf; @@ -26,6 +27,7 @@ use crate::infer::{InferCtxt, TyCtxtInferExt}; use crate::traits::error_reporting::TypeErrCtxtExt as _; use crate::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_errors::ErrorGuaranteed; +use rustc_middle::query::Providers; use rustc_middle::ty::fold::TypeFoldable; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable}; @@ -61,6 +63,7 @@ pub use self::specialize::{ pub use self::structural_match::{ search_for_adt_const_param_violation, search_for_structural_match_violation, }; +pub use self::structural_normalize::StructurallyNormalizeExt; pub use self::util::elaborate; pub use self::util::{expand_trait_aliases, TraitAliasExpander}; pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices}; @@ -142,35 +145,36 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>( fn pred_known_to_hold_modulo_regions<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>, + pred: impl ToPredicate<'tcx>, ) -> bool { - let has_non_region_infer = pred.has_non_region_infer(); let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred); let result = infcx.evaluate_obligation_no_overflow(&obligation); debug!(?result); - if result.must_apply_modulo_regions() && !has_non_region_infer { + if result.must_apply_modulo_regions() { true } else if result.may_apply() { - // Because of inference "guessing", selection can sometimes claim - // to succeed while the success requires a guess. To ensure - // this function's result remains infallible, we must confirm - // that guess. While imperfect, I believe this is sound. - - // The handling of regions in this area of the code is terrible, - // see issue #29149. We should be able to improve on this with - // NLL. - let ocx = ObligationCtxt::new(infcx); - ocx.register_obligation(obligation); - let errors = ocx.select_all_or_error(); - match errors.as_slice() { - [] => true, - errors => { - debug!(?errors); - false + // Sometimes obligations are ambiguous because the recursive evaluator + // is not smart enough, so we fall back to fulfillment when we're not certain + // that an obligation holds or not. Even still, we must make sure that + // the we do no inference in the process of checking this obligation. + let goal = infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); + infcx.probe(|_| { + let ocx = ObligationCtxt::new_in_snapshot(infcx); + ocx.register_obligation(obligation); + + let errors = ocx.select_all_or_error(); + match errors.as_slice() { + // Only known to hold if we did no inference. + [] => infcx.shallow_resolve(goal) == goal, + + errors => { + debug!(?errors); + false + } } - } + }) } else { false } @@ -498,10 +502,10 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI false } -pub fn provide(providers: &mut ty::query::Providers) { +pub fn provide(providers: &mut Providers) { object_safety::provide(providers); vtable::provide(providers); - *providers = ty::query::Providers { + *providers = Providers { specialization_graph_of: specialize::specialization_graph_provider, specializes: specialize::specializes, subst_and_check_impossible_predicates, diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs index 06d9c10386e..c81bf6ebc2e 100644 --- a/compiler/rustc_trait_selection/src/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -16,6 +16,7 @@ use crate::traits::{self, Obligation, ObligationCause}; use rustc_errors::{DelayDm, FatalError, MultiSpan}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_middle::query::Providers; use rustc_middle::ty::subst::{GenericArg, InternalSubsts}; use rustc_middle::ty::{ self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, @@ -947,7 +948,6 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>( }) } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = - ty::query::Providers { object_safety_violations, check_is_object_safe, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { object_safety_violations, check_is_object_safe, ..*providers }; } diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 8e684b7ac23..51069897120 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1543,7 +1543,10 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( // Check whether the self-type is itself a projection. // If so, extract what we know from the trait and try to come up with a good answer. let bounds = match *obligation.predicate.self_ty().kind() { - ty::Alias(_, ref data) => tcx.item_bounds(data.def_id).subst(tcx, data.substs), + // Excluding IATs here as they don't have meaningful item bounds. + ty::Alias(ty::Projection | ty::Opaque, ref data) => { + tcx.item_bounds(data.def_id).subst(tcx, data.substs) + } ty::Infer(ty::TyVar(_)) => { // If the self-type is an inference variable, then it MAY wind up // being a projected type, so induce an ambiguity. @@ -2260,7 +2263,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>( obligation, poly_cache_entry, e, ); debug!("confirm_param_env_candidate: {}", msg); - let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg); + let err = infcx.tcx.ty_error_with_message(obligation.cause.span, msg); Progress { term: err.into(), obligations: vec![] } } } diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index a8fb55df2d3..aa230936903 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -143,7 +143,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Before we go into the whole placeholder thing, just // quickly check if the self-type is a projection at all. match obligation.predicate.skip_binder().trait_ref.self_ty().kind() { - ty::Alias(..) => {} + // Excluding IATs here as they don't have meaningful item bounds. + ty::Alias(ty::Projection | ty::Opaque, _) => {} ty::Infer(ty::TyVar(_)) => { span_bug!( obligation.cause.span, diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 4dc84e0ad10..0d9f55d4c2e 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -29,9 +29,9 @@ use crate::traits::{ ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, ImplSourceConstDestructData, ImplSourceFnPointerData, ImplSourceFutureData, ImplSourceGeneratorData, ImplSourceObjectData, ImplSourceTraitAliasData, - ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation, - Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, - SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented, + ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, Obligation, + ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, SelectionError, + TraitNotObjectSafe, TraitObligation, Unimplemented, }; use super::BuiltinImplConditions; @@ -132,6 +132,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } }; + // The obligations returned by confirmation are recursively evaluated + // so we need to make sure they have the correct depth. + for subobligation in impl_src.borrow_nested_obligations_mut() { + subobligation.set_depth_from_parent(obligation.recursion_depth); + } + if !obligation.predicate.is_const_if_const() { // normalize nested predicates according to parent predicate's constness. impl_src = impl_src.map(|mut o| { @@ -156,7 +162,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let placeholder_self_ty = placeholder_trait_predicate.self_ty(); let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate); let (def_id, substs) = match *placeholder_self_ty.kind() { - ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs), + // Excluding IATs here as they don't have meaningful item bounds. + ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + (def_id, substs) + } _ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty), }; @@ -905,16 +914,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_err(|_| Unimplemented)?; nested.extend(obligations); - // Register one obligation for 'a: 'b. - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(source, target), - ); let outlives = ty::OutlivesPredicate(r_a, r_b); nested.push(Obligation::with_depth( tcx, - cause, + obligation.cause.clone(), obligation.recursion_depth + 1, obligation.param_env, obligation.predicate.rebind(outlives), @@ -1005,15 +1008,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { nested.extend(obligations); // Register one obligation for 'a: 'b. - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(source, target), - ); let outlives = ty::OutlivesPredicate(r_a, r_b); nested.push(Obligation::with_depth( tcx, - cause, + obligation.cause.clone(), obligation.recursion_depth + 1, obligation.param_env, obligation.predicate.rebind(outlives), @@ -1027,16 +1025,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { return Err(TraitNotObjectSafe(did)); } - let cause = ObligationCause::new( - obligation.cause.span, - obligation.cause.body_id, - ObjectCastObligation(source, target), - ); - let predicate_to_obligation = |predicate| { Obligation::with_depth( tcx, - cause.clone(), + obligation.cause.clone(), obligation.recursion_depth + 1, obligation.param_env, predicate, @@ -1056,7 +1048,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); // We can only make objects from sized types. - let tr = ty::TraitRef::from_lang_item(tcx, LangItem::Sized, cause.span, [source]); + let tr = ty::TraitRef::from_lang_item( + tcx, + LangItem::Sized, + obligation.cause.span, + [source], + ); nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx))); // If the type is `Foo + 'a`, ensure that the type diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index e4f5a84f424..b366bbd531b 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -537,14 +537,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &PredicateObligation<'tcx>, ) -> Result<EvaluationResult, OverflowError> { self.evaluation_probe(|this| { - if this.tcx().trait_solver_next() { - this.evaluate_predicates_recursively_in_new_solver([obligation.clone()]) + let goal = + this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env)); + let mut result = if this.tcx().trait_solver_next() { + this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])? } else { this.evaluate_predicate_recursively( TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()), obligation.clone(), - ) + )? + }; + // If the predicate has done any inference, then downgrade the + // result to ambiguous. + if this.infcx.shallow_resolve(goal) != goal { + result = result.max(EvaluatedToAmbig); } + Ok(result) }) } @@ -1645,7 +1653,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let tcx = self.infcx.tcx; let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { - ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs), + ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) => { + (def_id, substs) + } _ => { span_bug!( obligation.cause.span, @@ -2647,14 +2657,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> { let predicates = predicates.instantiate_own(tcx, substs); let mut obligations = Vec::with_capacity(predicates.len()); for (index, (predicate, span)) in predicates.into_iter().enumerate() { - let cause = cause.clone().derived_cause(parent_trait_pred, |derived| { - ImplDerivedObligation(Box::new(ImplDerivedObligationCause { - derived, - impl_or_alias_def_id: def_id, - impl_def_predicate_index: Some(index), - span, - })) - }); + let cause = + if Some(parent_trait_pred.def_id()) == tcx.lang_items().coerce_unsized_trait() { + cause.clone() + } else { + cause.clone().derived_cause(parent_trait_pred, |derived| { + ImplDerivedObligation(Box::new(ImplDerivedObligationCause { + derived, + impl_or_alias_def_id: def_id, + impl_def_predicate_index: Some(index), + span, + })) + }) + }; let predicate = normalize_with_depth_to( self, param_env, diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs new file mode 100644 index 00000000000..af8dd0da579 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs @@ -0,0 +1,55 @@ +use rustc_infer::infer::at::At; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::traits::{FulfillmentError, TraitEngine}; +use rustc_middle::ty::{self, Ty}; + +use crate::traits::{query::evaluate_obligation::InferCtxtExt, NormalizeExt, Obligation}; + +pub trait StructurallyNormalizeExt<'tcx> { + fn structurally_normalize( + &self, + ty: Ty<'tcx>, + fulfill_cx: &mut dyn TraitEngine<'tcx>, + ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>>; +} + +impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> { + fn structurally_normalize( + &self, + mut ty: Ty<'tcx>, + fulfill_cx: &mut dyn TraitEngine<'tcx>, + ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> { + assert!(!ty.is_ty_var(), "should have resolved vars before calling"); + + if self.infcx.tcx.trait_solver_next() { + while let ty::Alias(ty::Projection, projection_ty) = *ty.kind() { + let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::NormalizeProjectionType, + span: self.cause.span, + }); + let obligation = Obligation::new( + self.infcx.tcx, + self.cause.clone(), + self.param_env, + ty::Binder::dummy(ty::ProjectionPredicate { + projection_ty, + term: new_infer_ty.into(), + }), + ); + if self.infcx.predicate_may_hold(&obligation) { + fulfill_cx.register_predicate_obligation(self.infcx, obligation); + let errors = fulfill_cx.select_where_possible(self.infcx); + if !errors.is_empty() { + return Err(errors); + } + ty = self.infcx.resolve_vars_if_possible(new_infer_ty); + } else { + break; + } + } + Ok(ty) + } else { + Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx)) + } + } +} diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs index f7a3126b4aa..cc674ceee3d 100644 --- a/compiler/rustc_trait_selection/src/traits/vtable.rs +++ b/compiler/rustc_trait_selection/src/traits/vtable.rs @@ -4,6 +4,7 @@ use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_infer::traits::util::PredicateSet; use rustc_infer::traits::ImplSource; +use rustc_middle::query::Providers; use rustc_middle::ty::visit::TypeVisitableExt; use rustc_middle::ty::InternalSubsts; use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry}; @@ -379,8 +380,8 @@ pub(crate) fn count_own_vtable_entries<'tcx>( tcx.own_existential_vtable_entries(trait_ref.def_id()).len() } -pub(super) fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { +pub(super) fn provide(providers: &mut Providers) { + *providers = Providers { own_existential_vtable_entries, vtable_entries, vtable_trait_upcasting_coercion_new_vptr_slot, diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs index a5ebc26a8bc..8834449c9a4 100644 --- a/compiler/rustc_traits/src/chalk/mod.rs +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -7,8 +7,8 @@ pub(crate) mod db; pub(crate) mod lowering; use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind}; +use rustc_middle::query::Providers; use rustc_middle::traits::ChalkRustInterner; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitable}; use rustc_infer::infer::canonical::{ diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs index fcdffc7468b..83f6c7d07fe 100644 --- a/compiler/rustc_traits/src/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -2,7 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::InternalSubsts; use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs index e94c8efe69a..149dffc7e31 100644 --- a/compiler/rustc_traits/src/evaluate_obligation.rs +++ b/compiler/rustc_traits/src/evaluate_obligation.rs @@ -1,5 +1,5 @@ use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_span::source_map::DUMMY_SP; use rustc_trait_selection::traits::query::CanonicalPredicateGoal; diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs index f5bba14d2fb..0c2bb863e1f 100644 --- a/compiler/rustc_traits/src/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -6,7 +6,7 @@ use rustc_infer::infer::canonical::{self, Canonical}; use rustc_infer::infer::outlives::components::{push_outlives_components, Component}; use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::query::OutlivesBound; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::source_map::DUMMY_SP; diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs index 8bea5588ae7..b0f9c57154f 100644 --- a/compiler/rustc_traits/src/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -23,7 +23,7 @@ mod type_op; pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause}; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; pub fn provide(p: &mut Providers) { dropck_outlives::provide(p); diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs index 5da0f16c2bf..94c33efaeff 100644 --- a/compiler/rustc_traits/src/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -1,6 +1,6 @@ use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::query::Providers; use rustc_middle::traits::query::NoSolution; -use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt; use rustc_trait_selection::traits::{Normalized, ObligationCause}; diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs index 36d80a06ee7..b552ba41acd 100644 --- a/compiler/rustc_traits/src/normalize_projection_ty.rs +++ b/compiler/rustc_traits/src/normalize_projection_ty.rs @@ -1,6 +1,6 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{ParamEnvAnd, TyCtxt}; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::{ diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs index 19622112f2a..70dc7ccec63 100644 --- a/compiler/rustc_traits/src/type_op.rs +++ b/compiler/rustc_traits/src/type_op.rs @@ -2,7 +2,7 @@ use rustc_hir as hir; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt}; use rustc_infer::traits::ObligationCauseCode; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{ParamEnvAnd, Predicate}; use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType}; diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl index 15a14112f4a..5bc3e3c00c9 100644 --- a/compiler/rustc_ty_utils/messages.ftl +++ b/compiler/rustc_ty_utils/messages.ftl @@ -55,3 +55,11 @@ ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes} ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}` + +ty_utils_impl_trait_duplicate_arg = non-defining opaque type use in defining scope + .label = generic argument `{$arg}` used twice + .note = for this opaque type + +ty_utils_impl_trait_not_param = non-defining opaque type use in defining scope + .label = argument `{$arg}` is not a generic parameter + .note = for this opaque type diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index 271284b2d81..442d041a8a7 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -1,5 +1,6 @@ use rustc_hir as hir; use rustc_hir::lang_items::LangItem; +use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout, }; @@ -14,8 +15,8 @@ use rustc_target::spec::abi::Abi as SpecAbi; use std::iter; -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers }; } // NOTE(eddyb) this is private to avoid using it from outside of diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index 9029ba2a51a..ed574f22e61 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -4,11 +4,12 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId}; use rustc_hir::definitions::DefPathData; use rustc_hir::intravisit::{self, Visitor}; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, ImplTraitInTraitData, InternalSubsts, TyCtxt}; use rustc_span::symbol::kw; -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { +pub fn provide(providers: &mut Providers) { + *providers = Providers { associated_item, associated_item_def_ids, associated_items, diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs index 3b1abdcb24f..51b908881eb 100644 --- a/compiler/rustc_ty_utils/src/common_traits.rs +++ b/compiler/rustc_ty_utils/src/common_traits.rs @@ -2,6 +2,7 @@ use rustc_hir::lang_items::LangItem; use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_trait_selection::traits; @@ -32,12 +33,6 @@ fn is_item_raw<'tcx>( traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id) } -pub(crate) fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { - is_copy_raw, - is_sized_raw, - is_freeze_raw, - is_unpin_raw, - ..*providers - }; +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { is_copy_raw, is_sized_raw, is_freeze_raw, is_unpin_raw, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs index 3dd1d056be2..1219bb40098 100644 --- a/compiler/rustc_ty_utils/src/consts.rs +++ b/compiler/rustc_ty_utils/src/consts.rs @@ -2,6 +2,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput}; +use rustc_middle::query::Providers; use rustc_middle::thir::visit; use rustc_middle::thir::visit::Visitor; use rustc_middle::ty::abstract_const::CastKind; @@ -115,9 +116,7 @@ fn recurse_build<'tcx>( let sp = node.span; match tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) { Ok(c) => c, - Err(LitToConstError::Reported(guar)) => { - tcx.const_error_with_guaranteed(node.ty, guar) - } + Err(LitToConstError::Reported(guar)) => tcx.const_error(node.ty, guar), Err(LitToConstError::TypeError) => { bug!("encountered type error in lit_to_const") } @@ -423,6 +422,6 @@ pub fn thir_abstract_const( Ok(Some(ty::EarlyBinder(recurse_build(tcx, body, body_id, root_span)?))) } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { destructure_const, thir_abstract_const, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { destructure_const, thir_abstract_const, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs index 3d3fc50e6e5..553bf40ef3a 100644 --- a/compiler/rustc_ty_utils/src/errors.rs +++ b/compiler/rustc_ty_utils/src/errors.rs @@ -1,7 +1,7 @@ //! Errors emitted by ty_utils use rustc_macros::{Diagnostic, Subdiagnostic}; -use rustc_middle::ty::Ty; +use rustc_middle::ty::{GenericArg, Ty}; use rustc_span::Span; #[derive(Diagnostic)] @@ -100,3 +100,25 @@ pub struct NonPrimitiveSimdType<'tcx> { pub ty: Ty<'tcx>, pub e_ty: Ty<'tcx>, } + +#[derive(Diagnostic)] +#[diag(ty_utils_impl_trait_duplicate_arg)] +pub struct DuplicateArg<'tcx> { + pub arg: GenericArg<'tcx>, + #[primary_span] + #[label] + pub span: Span, + #[note] + pub opaque_span: Span, +} + +#[derive(Diagnostic)] +#[diag(ty_utils_impl_trait_not_param)] +pub struct NotParam<'tcx> { + pub arg: GenericArg<'tcx>, + #[primary_span] + #[label] + pub span: Span, + #[note] + pub opaque_span: Span, +} diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 5ca5d14337c..081be065864 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -1,8 +1,9 @@ use rustc_hir::{def::DefKind, def_id::DefId}; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { assumed_wf_types, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { assumed_wf_types, ..*providers }; } fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> { diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index eb3c21163ab..36a20c78fcc 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -1,6 +1,7 @@ use rustc_errors::ErrorGuaranteed; use rustc_hir::def_id::DefId; use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::query::Providers; use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitableExt}; @@ -319,6 +320,6 @@ fn resolve_associated_item<'tcx>( }) } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { resolve_instance, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { resolve_instance, ..*providers }; } diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs index f7c75583f60..16cd8bc8e69 100644 --- a/compiler/rustc_ty_utils/src/layout.rs +++ b/compiler/rustc_ty_utils/src/layout.rs @@ -3,6 +3,7 @@ use rustc_hir as hir; use rustc_index::bit_set::BitSet; use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::{GeneratorLayout, GeneratorSavedLocal}; +use rustc_middle::query::Providers; use rustc_middle::ty::layout::{ IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES, }; @@ -22,8 +23,8 @@ use crate::errors::{ }; use crate::layout_sanity_check::sanity_check_layout; -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { layout_of, ..*providers }; +pub fn provide(providers: &mut Providers) { + *providers = Providers { layout_of, ..*providers }; } #[instrument(skip(tcx, query), level = "debug")] diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 73a2f6af579..55b8857ed39 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -21,7 +21,7 @@ extern crate tracing; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; mod abi; mod assoc; @@ -33,6 +33,7 @@ pub mod instance; mod layout; mod layout_sanity_check; mod needs_drop; +mod opaque_types; pub mod representability; mod structural_match; mod ty; @@ -47,6 +48,7 @@ pub fn provide(providers: &mut Providers) { implied_bounds::provide(providers); layout::provide(providers); needs_drop::provide(providers); + opaque_types::provide(providers); representability::provide(providers); ty::provide(providers); instance::provide(providers); diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index a04f85afb9e..1f9701b9322 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; +use rustc_middle::query::Providers; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop}; use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt}; @@ -323,8 +324,8 @@ fn adt_significant_drop_tys( .map(|components| tcx.mk_type_list(&components)) } -pub(crate) fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { +pub(crate) fn provide(providers: &mut Providers) { + *providers = Providers { needs_drop_raw, has_significant_drop_raw, adt_drop_tys, diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs new file mode 100644 index 00000000000..4e91dd380e8 --- /dev/null +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -0,0 +1,198 @@ +use rustc_data_structures::fx::FxHashSet; +use rustc_errors::ErrorGuaranteed; +use rustc_hir::{def::DefKind, def_id::LocalDefId}; +use rustc_middle::query::Providers; +use rustc_middle::ty::util::{CheckRegions, NotUniqueParam}; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; +use rustc_span::Span; +use rustc_type_ir::AliasKind; +use std::ops::ControlFlow; + +use crate::errors::{DuplicateArg, NotParam}; + +struct OpaqueTypeCollector<'tcx> { + tcx: TyCtxt<'tcx>, + opaques: Vec<LocalDefId>, + /// The `DefId` of the item which we are collecting opaque types for. + item: LocalDefId, + + /// Avoid infinite recursion due to recursive declarations. + seen: FxHashSet<LocalDefId>, +} + +impl<'tcx> OpaqueTypeCollector<'tcx> { + fn collect( + tcx: TyCtxt<'tcx>, + item: LocalDefId, + val: ty::Binder<'tcx, impl TypeVisitable<TyCtxt<'tcx>>>, + ) -> Vec<LocalDefId> { + let mut collector = Self { tcx, opaques: Vec::new(), item, seen: Default::default() }; + val.skip_binder().visit_with(&mut collector); + collector.opaques + } + + fn span(&self) -> Span { + self.tcx.def_span(self.item) + } + + fn parent(&self) -> Option<LocalDefId> { + match self.tcx.def_kind(self.item) { + DefKind::Fn => None, + DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { + Some(self.tcx.local_parent(self.item)) + } + other => span_bug!( + self.tcx.def_span(self.item), + "unhandled item with opaque types: {other:?}" + ), + } + } +} + +impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> { + type BreakTy = ErrorGuaranteed; + + #[instrument(skip(self), ret, level = "trace")] + fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<ErrorGuaranteed> { + match t.kind() { + ty::Alias(AliasKind::Opaque, alias_ty) if alias_ty.def_id.is_local() => { + if !self.seen.insert(alias_ty.def_id.expect_local()) { + return ControlFlow::Continue(()); + } + match self.tcx.uses_unique_generic_params(alias_ty.substs, CheckRegions::Bound) { + Ok(()) => { + // FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not + // supported at all, so this is sound to do, but once we want to support them, you'll + // start seeing the error below. + + self.opaques.push(alias_ty.def_id.expect_local()); + + // Collect opaque types nested within the associated type bounds of this opaque type. + for (pred, _span) in self + .tcx + .explicit_item_bounds(alias_ty.def_id) + .subst_iter_copied(self.tcx, alias_ty.substs) + { + trace!(?pred); + pred.visit_with(self)?; + } + + ControlFlow::Continue(()) + } + Err(NotUniqueParam::NotParam(arg)) => { + let err = self.tcx.sess.emit_err(NotParam { + arg, + span: self.span(), + opaque_span: self.tcx.def_span(alias_ty.def_id), + }); + ControlFlow::Break(err) + } + Err(NotUniqueParam::DuplicateParam(arg)) => { + let err = self.tcx.sess.emit_err(DuplicateArg { + arg, + span: self.span(), + opaque_span: self.tcx.def_span(alias_ty.def_id), + }); + ControlFlow::Break(err) + } + } + } + ty::Alias(AliasKind::Projection, alias_ty) => { + if let Some(parent) = self.parent() { + trace!(?alias_ty); + let (trait_ref, own_substs) = alias_ty.trait_ref_and_own_substs(self.tcx); + + trace!(?trait_ref, ?own_substs); + // This avoids having to do normalization of `Self::AssocTy` by only + // supporting the case of a method defining opaque types from assoc types + // in the same impl block. + if trait_ref.self_ty() == self.tcx.type_of(parent).subst_identity() { + for assoc in self.tcx.associated_items(parent).in_definition_order() { + trace!(?assoc); + if assoc.trait_item_def_id == Some(alias_ty.def_id) { + // We reconstruct the generic args of the associated type within the impl + // from the impl's generics and the generic args passed to the type via the + // projection. + let substs = ty::InternalSubsts::identity_for_item( + self.tcx, + parent.to_def_id(), + ); + trace!(?substs); + let substs: Vec<_> = + substs.iter().chain(own_substs.iter().copied()).collect(); + trace!(?substs); + // Find opaque types in this associated type. + return self + .tcx + .type_of(assoc.def_id) + .subst(self.tcx, &substs) + .visit_with(self); + } + } + } + } + t.super_visit_with(self) + } + _ => t.super_visit_with(self), + } + } +} + +fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] { + let kind = tcx.def_kind(item); + trace!(?kind); + // FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT and impl trait in assoc types. + match kind { + // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds` + DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => { + let defined_opaques = match kind { + DefKind::Fn => { + OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity()) + } + DefKind::AssocFn => { + OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity()) + } + DefKind::AssocTy | DefKind::AssocConst => OpaqueTypeCollector::collect( + tcx, + item, + ty::Binder::dummy(tcx.type_of(item).subst_identity()), + ), + _ => unreachable!(), + }; + tcx.arena.alloc_from_iter(defined_opaques) + } + DefKind::Mod + | DefKind::Struct + | DefKind::Union + | DefKind::Enum + | DefKind::Variant + | DefKind::Trait + | DefKind::TyAlias + | DefKind::ForeignTy + | DefKind::TraitAlias + | DefKind::TyParam + | DefKind::Const + | DefKind::ConstParam + | DefKind::Static(_) + | DefKind::Ctor(_, _) + | DefKind::Macro(_) + | DefKind::ExternCrate + | DefKind::Use + | DefKind::ForeignMod + | DefKind::AnonConst + | DefKind::InlineConst + | DefKind::OpaqueTy + | DefKind::ImplTraitPlaceholder + | DefKind::Field + | DefKind::LifetimeParam + | DefKind::GlobalAsm + | DefKind::Impl { .. } + | DefKind::Closure + | DefKind::Generator => &[], + } +} + +pub(super) fn provide(providers: &mut Providers) { + *providers = Providers { opaque_types_defined_by, ..*providers }; +} diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index 26d6deab883..0b5e27c2c74 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -2,7 +2,7 @@ use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Representability, Ty, TyCtxt}; use rustc_span::def_id::LocalDefId; diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs index 9cb0fc10594..215acbe2c8f 100644 --- a/compiler/rustc_ty_utils/src/structural_match.rs +++ b/compiler/rustc_ty_utils/src/structural_match.rs @@ -1,5 +1,5 @@ use rustc_hir::lang_items::LangItem; -use rustc_middle::ty::query::Providers; +use rustc_middle::query::Providers; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_infer::infer::TyCtxtInferExt; diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs index 78efcce572d..65dc3c39c6a 100644 --- a/compiler/rustc_ty_utils/src/ty.rs +++ b/compiler/rustc_ty_utils/src/ty.rs @@ -2,6 +2,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_index::bit_set::BitSet; +use rustc_middle::query::Providers; use rustc_middle::ty::{ self, Binder, EarlyBinder, ImplTraitInTraitData, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, @@ -566,8 +567,8 @@ fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BitSet<u32 unsizing_params } -pub fn provide(providers: &mut ty::query::Providers) { - *providers = ty::query::Providers { +pub fn provide(providers: &mut Providers) { + *providers = Providers { asyncness, adt_sized_constraint, param_env, diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs index c9675f93f95..45a2e9023c9 100644 --- a/compiler/rustc_type_ir/src/structural_impls.rs +++ b/compiler/rustc_type_ir/src/structural_impls.rs @@ -21,6 +21,7 @@ TrivialTypeTraversalImpls! { (), bool, usize, + u8, u16, u32, u64, diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index 2daef82d6f1..1f8a1ecba6e 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -3021,7 +3021,7 @@ impl<'a, K, V, A> CursorMut<'a, K, V, A> { }) } - /// Returns a mutable reference to the of the element that the cursor is + /// Returns a mutable reference to the key of the element that the cursor is /// currently pointing to. /// /// This returns `None` if the cursor is currently pointing to the diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 088139a6907..498fbd93288 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -2623,6 +2623,15 @@ impl ToString for String { } } +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "fmt_arguments_to_string_specialization", since = "CURRENT_RUSTC_VERSION")] +impl ToString for fmt::Arguments<'_> { + #[inline] + fn to_string(&self) -> String { + crate::fmt::format(*self) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<str> for String { #[inline] diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 7347980abbc..bfdb7a92bef 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -502,6 +502,7 @@ impl<T> Arc<T> { /// assert_eq!(*five, 5) /// ``` #[cfg(not(no_global_oom_handling))] + #[inline] #[unstable(feature = "new_uninit", issue = "63291")] #[must_use] pub fn new_uninit() -> Arc<mem::MaybeUninit<T>> { @@ -535,6 +536,7 @@ impl<T> Arc<T> { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] + #[inline] #[unstable(feature = "new_uninit", issue = "63291")] #[must_use] pub fn new_zeroed() -> Arc<mem::MaybeUninit<T>> { @@ -844,6 +846,7 @@ impl<T> Arc<[T]> { /// assert_eq!(*values, [1, 2, 3]) /// ``` #[cfg(not(no_global_oom_handling))] + #[inline] #[unstable(feature = "new_uninit", issue = "63291")] #[must_use] pub fn new_uninit_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> { @@ -871,6 +874,7 @@ impl<T> Arc<[T]> { /// /// [zeroed]: mem::MaybeUninit::zeroed #[cfg(not(no_global_oom_handling))] + #[inline] #[unstable(feature = "new_uninit", issue = "63291")] #[must_use] pub fn new_zeroed_slice(len: usize) -> Arc<[mem::MaybeUninit<T>]> { @@ -1300,10 +1304,10 @@ impl<T: ?Sized> Arc<T> { mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner<T>, ) -> *mut ArcInner<T> { let layout = arcinner_layout_for_value_layout(value_layout); - unsafe { - Arc::try_allocate_for_layout(value_layout, allocate, mem_to_arcinner) - .unwrap_or_else(|_| handle_alloc_error(layout)) - } + + let ptr = allocate(layout).unwrap_or_else(|_| handle_alloc_error(layout)); + + unsafe { Self::initialize_arcinner(ptr, layout, mem_to_arcinner) } } /// Allocates an `ArcInner<T>` with sufficient space for @@ -1321,7 +1325,16 @@ impl<T: ?Sized> Arc<T> { let ptr = allocate(layout)?; - // Initialize the ArcInner + let inner = unsafe { Self::initialize_arcinner(ptr, layout, mem_to_arcinner) }; + + Ok(inner) + } + + unsafe fn initialize_arcinner( + ptr: NonNull<[u8]>, + layout: Layout, + mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner<T>, + ) -> *mut ArcInner<T> { let inner = mem_to_arcinner(ptr.as_non_null_ptr().as_ptr()); debug_assert_eq!(unsafe { Layout::for_value(&*inner) }, layout); @@ -1330,7 +1343,7 @@ impl<T: ?Sized> Arc<T> { ptr::write(&mut (*inner).weak, atomic::AtomicUsize::new(1)); } - Ok(inner) + inner } /// Allocates an `ArcInner<T>` with sufficient space for an unsized inner value. diff --git a/library/alloc/src/vec/in_place_collect.rs b/library/alloc/src/vec/in_place_collect.rs index 2f1ee8b0353..5ecd0479971 100644 --- a/library/alloc/src/vec/in_place_collect.rs +++ b/library/alloc/src/vec/in_place_collect.rs @@ -178,7 +178,8 @@ where ) }; - let len = SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf, dst_end); + // SAFETY: `dst_buf` and `dst_end` are the start and end of the buffer. + let len = unsafe { SpecInPlaceCollect::collect_in_place(&mut iterator, dst_buf, dst_end) }; let src = unsafe { iterator.as_inner().as_into_iter() }; // check if SourceIter contract was upheld @@ -239,7 +240,7 @@ trait SpecInPlaceCollect<T, I>: Iterator<Item = T> { /// `Iterator::__iterator_get_unchecked` calls with a `TrustedRandomAccessNoCoerce` bound /// on `I` which means the caller of this method must take the safety conditions /// of that trait into consideration. - fn collect_in_place(&mut self, dst: *mut T, end: *const T) -> usize; + unsafe fn collect_in_place(&mut self, dst: *mut T, end: *const T) -> usize; } impl<T, I> SpecInPlaceCollect<T, I> for I @@ -247,7 +248,7 @@ where I: Iterator<Item = T>, { #[inline] - default fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize { + default unsafe fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize { // use try-fold since // - it vectorizes better for some iterator adapters // - unlike most internal iteration methods, it only takes a &mut self @@ -265,7 +266,7 @@ where I: Iterator<Item = T> + TrustedRandomAccessNoCoerce, { #[inline] - fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize { + unsafe fn collect_in_place(&mut self, dst_buf: *mut T, end: *const T) -> usize { let len = self.size(); let mut drop_guard = InPlaceDrop { inner: dst_buf, dst: dst_buf }; for i in 0..len { diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index 97da6f06b70..82f30a26d41 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -646,14 +646,14 @@ impl<T, A: Allocator> Vec<T, A> { /// /// // The vector contains no items, even though it has capacity for more /// assert_eq!(vec.len(), 0); - /// assert_eq!(vec.capacity(), 10); + /// assert!(vec.capacity() >= 10); /// /// // These are all done without reallocating... /// for i in 0..10 { /// vec.push(i); /// } /// assert_eq!(vec.len(), 10); - /// assert_eq!(vec.capacity(), 10); + /// assert!(vec.capacity() >= 10); /// /// // ...but this may make the vector reallocate /// vec.push(11); @@ -877,7 +877,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` /// let mut vec: Vec<i32> = Vec::with_capacity(10); /// vec.push(42); - /// assert_eq!(vec.capacity(), 10); + /// assert!(vec.capacity() >= 10); /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -1028,7 +1028,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` /// let mut vec = Vec::with_capacity(10); /// vec.extend([1, 2, 3]); - /// assert_eq!(vec.capacity(), 10); + /// assert!(vec.capacity() >= 10); /// vec.shrink_to_fit(); /// assert!(vec.capacity() >= 3); /// ``` @@ -1055,7 +1055,7 @@ impl<T, A: Allocator> Vec<T, A> { /// ``` /// let mut vec = Vec::with_capacity(10); /// vec.extend([1, 2, 3]); - /// assert_eq!(vec.capacity(), 10); + /// assert!(vec.capacity() >= 10); /// vec.shrink_to(4); /// assert!(vec.capacity() >= 4); /// vec.shrink_to(0); @@ -1090,7 +1090,7 @@ impl<T, A: Allocator> Vec<T, A> { /// let mut vec = Vec::with_capacity(10); /// vec.extend([1, 2, 3]); /// - /// assert_eq!(vec.capacity(), 10); + /// assert!(vec.capacity() >= 10); /// let slice = vec.into_boxed_slice(); /// assert_eq!(slice.into_vec().capacity(), 3); /// ``` diff --git a/library/core/benches/fmt.rs b/library/core/benches/fmt.rs index ff726ff7559..d1cdb12e50f 100644 --- a/library/core/benches/fmt.rs +++ b/library/core/benches/fmt.rs @@ -1,13 +1,13 @@ use std::fmt::{self, Write as FmtWrite}; use std::io::{self, Write as IoWrite}; -use test::Bencher; +use test::{black_box, Bencher}; #[bench] fn write_vec_value(bh: &mut Bencher) { bh.iter(|| { let mut mem = Vec::new(); for _ in 0..1000 { - mem.write_all("abc".as_bytes()).unwrap(); + mem.write_all(black_box("abc").as_bytes()).unwrap(); } }); } @@ -18,7 +18,7 @@ fn write_vec_ref(bh: &mut Bencher) { let mut mem = Vec::new(); let wr = &mut mem as &mut dyn io::Write; for _ in 0..1000 { - wr.write_all("abc".as_bytes()).unwrap(); + wr.write_all(black_box("abc").as_bytes()).unwrap(); } }); } @@ -29,7 +29,7 @@ fn write_vec_macro1(bh: &mut Bencher) { let mut mem = Vec::new(); let wr = &mut mem as &mut dyn io::Write; for _ in 0..1000 { - write!(wr, "abc").unwrap(); + write!(wr, "{}", black_box("abc")).unwrap(); } }); } @@ -40,7 +40,7 @@ fn write_vec_macro2(bh: &mut Bencher) { let mut mem = Vec::new(); let wr = &mut mem as &mut dyn io::Write; for _ in 0..1000 { - write!(wr, "{}", "abc").unwrap(); + write!(wr, "{}", black_box("abc")).unwrap(); } }); } @@ -51,7 +51,7 @@ fn write_vec_macro_debug(bh: &mut Bencher) { let mut mem = Vec::new(); let wr = &mut mem as &mut dyn io::Write; for _ in 0..1000 { - write!(wr, "{:?}", "☃").unwrap(); + write!(wr, "{:?}", black_box("☃")).unwrap(); } }); } @@ -61,7 +61,7 @@ fn write_str_value(bh: &mut Bencher) { bh.iter(|| { let mut mem = String::new(); for _ in 0..1000 { - mem.write_str("abc").unwrap(); + mem.write_str(black_box("abc")).unwrap(); } }); } @@ -72,7 +72,7 @@ fn write_str_ref(bh: &mut Bencher) { let mut mem = String::new(); let wr = &mut mem as &mut dyn fmt::Write; for _ in 0..1000 { - wr.write_str("abc").unwrap(); + wr.write_str(black_box("abc")).unwrap(); } }); } @@ -82,7 +82,7 @@ fn write_str_macro1(bh: &mut Bencher) { bh.iter(|| { let mut mem = String::new(); for _ in 0..1000 { - write!(mem, "abc").unwrap(); + write!(mem, "{}", black_box("abc")).unwrap(); } }); } @@ -93,7 +93,7 @@ fn write_str_macro2(bh: &mut Bencher) { let mut mem = String::new(); let wr = &mut mem as &mut dyn fmt::Write; for _ in 0..1000 { - write!(wr, "{}", "abc").unwrap(); + write!(wr, "{}", black_box("abc")).unwrap(); } }); } @@ -104,7 +104,7 @@ fn write_str_macro_debug(bh: &mut Bencher) { let mut mem = String::new(); let wr = &mut mem as &mut dyn fmt::Write; for _ in 0..1000 { - write!(wr, "{:?}", "☃").unwrap(); + write!(wr, "{:?}", black_box("☃")).unwrap(); } }); } @@ -115,7 +115,7 @@ fn write_str_macro_debug_ascii(bh: &mut Bencher) { let mut mem = String::new(); let wr = &mut mem as &mut dyn fmt::Write; for _ in 0..1000 { - write!(wr, "{:?}", "Hello, World!").unwrap(); + write!(wr, "{:?}", black_box("Hello, World!")).unwrap(); } }); } diff --git a/library/core/benches/iter.rs b/library/core/benches/iter.rs index 9193c79bee8..60ef83223d1 100644 --- a/library/core/benches/iter.rs +++ b/library/core/benches/iter.rs @@ -404,7 +404,7 @@ fn bench_trusted_random_access_adapters(b: &mut Bencher) { /// Exercises the iter::Copied specialization for slice::Iter #[bench] -fn bench_copied_chunks(b: &mut Bencher) { +fn bench_next_chunk_copied(b: &mut Bencher) { let v = vec![1u8; 1024]; b.iter(|| { @@ -421,7 +421,7 @@ fn bench_copied_chunks(b: &mut Bencher) { /// Exercises the TrustedRandomAccess specialization in ArrayChunks #[bench] -fn bench_trusted_random_access_chunks(b: &mut Bencher) { +fn bench_next_chunk_trusted_random_access(b: &mut Bencher) { let v = vec![1u8; 1024]; b.iter(|| { @@ -437,3 +437,45 @@ fn bench_trusted_random_access_chunks(b: &mut Bencher) { .sum::<Wrapping<u64>>() }) } + +#[bench] +fn bench_next_chunk_filter_even(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter(|&&i| i % 2 == 0).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_predictably_true(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter(|&&i| i < 100).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_mostly_false(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter(|&&i| i > 900).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_map_even(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter_map(|&i| (i % 2 == 0).then(|| i)).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_map_predictably_true(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter_map(|&i| (i < 100).then(|| i)).next_chunk::<32>()) +} + +#[bench] +fn bench_next_chunk_filter_map_mostly_false(b: &mut Bencher) { + let a = (0..1024).next_chunk::<1024>().unwrap(); + + b.iter(|| black_box(&a).iter().filter_map(|&i| (i > 900).then(|| i)).next_chunk::<32>()) +} diff --git a/library/core/benches/num/dec2flt/mod.rs b/library/core/benches/num/dec2flt/mod.rs index 305baa68729..fb4a786b27e 100644 --- a/library/core/benches/num/dec2flt/mod.rs +++ b/library/core/benches/num/dec2flt/mod.rs @@ -1,57 +1,57 @@ -use test::Bencher; +use test::{black_box, Bencher}; #[bench] fn bench_0(b: &mut Bencher) { - b.iter(|| "0.0".parse::<f64>()); + b.iter(|| black_box("0.0").parse::<f64>()); } #[bench] fn bench_42(b: &mut Bencher) { - b.iter(|| "42".parse::<f64>()); + b.iter(|| black_box("42").parse::<f64>()); } #[bench] fn bench_huge_int(b: &mut Bencher) { // 2^128 - 1 - b.iter(|| "170141183460469231731687303715884105727".parse::<f64>()); + b.iter(|| black_box("170141183460469231731687303715884105727").parse::<f64>()); } #[bench] fn bench_short_decimal(b: &mut Bencher) { - b.iter(|| "1234.5678".parse::<f64>()); + b.iter(|| black_box("1234.5678").parse::<f64>()); } #[bench] fn bench_pi_long(b: &mut Bencher) { - b.iter(|| "3.14159265358979323846264338327950288".parse::<f64>()); + b.iter(|| black_box("3.14159265358979323846264338327950288").parse::<f64>()); } #[bench] fn bench_pi_short(b: &mut Bencher) { - b.iter(|| "3.141592653589793".parse::<f64>()) + b.iter(|| black_box("3.141592653589793").parse::<f64>()) } #[bench] fn bench_1e150(b: &mut Bencher) { - b.iter(|| "1e150".parse::<f64>()); + b.iter(|| black_box("1e150").parse::<f64>()); } #[bench] fn bench_long_decimal_and_exp(b: &mut Bencher) { - b.iter(|| "727501488517303786137132964064381141071e-123".parse::<f64>()); + b.iter(|| black_box("727501488517303786137132964064381141071e-123").parse::<f64>()); } #[bench] fn bench_min_subnormal(b: &mut Bencher) { - b.iter(|| "5e-324".parse::<f64>()); + b.iter(|| black_box("5e-324").parse::<f64>()); } #[bench] fn bench_min_normal(b: &mut Bencher) { - b.iter(|| "2.2250738585072014e-308".parse::<f64>()); + b.iter(|| black_box("2.2250738585072014e-308").parse::<f64>()); } #[bench] fn bench_max(b: &mut Bencher) { - b.iter(|| "1.7976931348623157e308".parse::<f64>()); + b.iter(|| black_box("1.7976931348623157e308").parse::<f64>()); } diff --git a/library/core/benches/num/flt2dec/mod.rs b/library/core/benches/num/flt2dec/mod.rs index 32fd5e626bc..1a330ef5fe5 100644 --- a/library/core/benches/num/flt2dec/mod.rs +++ b/library/core/benches/num/flt2dec/mod.rs @@ -7,7 +7,7 @@ use core::num::flt2dec::MAX_SIG_DIGITS; use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded}; use std::io::Write; use std::vec::Vec; -use test::Bencher; +use test::{black_box, Bencher}; pub fn decode_finite<T: DecodableFloat>(v: T) -> Decoded { match decode(v).1 { @@ -22,7 +22,7 @@ fn bench_small_shortest(b: &mut Bencher) { b.iter(|| { buf.clear(); - write!(&mut buf, "{}", 3.1415926f64).unwrap() + write!(black_box(&mut buf), "{}", black_box(3.1415926f64)).unwrap() }); } @@ -32,6 +32,6 @@ fn bench_big_shortest(b: &mut Bencher) { b.iter(|| { buf.clear(); - write!(&mut buf, "{}", f64::MAX).unwrap() + write!(black_box(&mut buf), "{}", black_box(f64::MAX)).unwrap() }); } diff --git a/library/core/benches/num/mod.rs b/library/core/benches/num/mod.rs index 2f9cad2725d..b97014d9bf9 100644 --- a/library/core/benches/num/mod.rs +++ b/library/core/benches/num/mod.rs @@ -3,7 +3,7 @@ mod flt2dec; mod int_log; use std::str::FromStr; -use test::Bencher; +use test::{black_box, Bencher}; const ASCII_NUMBERS: [&str; 19] = [ "0", @@ -36,7 +36,7 @@ macro_rules! from_str_bench { .iter() .cycle() .take(5_000) - .filter_map(|s| <$t>::from_str(s).ok()) + .filter_map(|s| <$t>::from_str(black_box(s)).ok()) .max() }) } @@ -52,7 +52,7 @@ macro_rules! from_str_radix_bench { .iter() .cycle() .take(5_000) - .filter_map(|s| <$t>::from_str_radix(s, $radix).ok()) + .filter_map(|s| <$t>::from_str_radix(black_box(s), $radix).ok()) .max() }) } diff --git a/library/core/src/any.rs b/library/core/src/any.rs index bb93ea509d8..d1c1ae6526b 100644 --- a/library/core/src/any.rs +++ b/library/core/src/any.rs @@ -866,7 +866,7 @@ where /// /// A data provider provides values by calling this type's provide methods. #[unstable(feature = "provide_any", issue = "96024")] -#[repr(transparent)] +#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 pub struct Demand<'a>(dyn Erased<'a> + 'a); impl<'a> Demand<'a> { diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index 7fd14a7e1ea..ef8e4d098ed 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -91,7 +91,7 @@ pub struct EscapeDefault(escape::EscapeIterInner<4>); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn escape_default(c: u8) -> EscapeDefault { - let mut data = [0; 4]; + let mut data = [Char::Null; 4]; let range = escape::escape_ascii_into(&mut data, c); EscapeDefault(escape::EscapeIterInner::new(data, range)) } diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index a96dfafd9c4..744767aae44 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -2030,6 +2030,27 @@ impl<T> UnsafeCell<T> { } impl<T: ?Sized> UnsafeCell<T> { + /// Converts from `&mut T` to `&mut UnsafeCell<T>`. + /// + /// # Examples + /// + /// ``` + /// # #![feature(unsafe_cell_from_mut)] + /// use std::cell::UnsafeCell; + /// + /// let mut val = 42; + /// let uc = UnsafeCell::from_mut(&mut val); + /// + /// *uc.get_mut() -= 1; + /// assert_eq!(*uc.get_mut(), 41); + /// ``` + #[inline(always)] + #[unstable(feature = "unsafe_cell_from_mut", issue = "111645")] + pub const fn from_mut(value: &mut T) -> &mut UnsafeCell<T> { + // SAFETY: `UnsafeCell<T>` has the same memory layout as `T` due to #[repr(transparent)]. + unsafe { &mut *(value as *mut T as *mut UnsafeCell<T>) } + } + /// Gets a mutable pointer to the wrapped value. /// /// This can be cast to a pointer of any kind. @@ -2100,6 +2121,8 @@ impl<T: ?Sized> UnsafeCell<T> { /// /// let m = MaybeUninit::<UnsafeCell<i32>>::uninit(); /// unsafe { UnsafeCell::raw_get(m.as_ptr()).write(5); } + /// // avoid below which references to uninitialized data + /// // unsafe { UnsafeCell::get(&*m.as_ptr()).write(5); } /// let uc = unsafe { m.assume_init() }; /// /// assert_eq!(uc.into_inner(), 5); diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index 1dfa9c34db1..515b8d20ead 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -392,13 +392,13 @@ impl char { #[inline] pub(crate) fn escape_debug_ext(self, args: EscapeDebugExtArgs) -> EscapeDebug { match self { - '\0' => EscapeDebug::backslash(b'0'), - '\t' => EscapeDebug::backslash(b't'), - '\r' => EscapeDebug::backslash(b'r'), - '\n' => EscapeDebug::backslash(b'n'), - '\\' => EscapeDebug::backslash(b'\\'), - '"' if args.escape_double_quote => EscapeDebug::backslash(b'"'), - '\'' if args.escape_single_quote => EscapeDebug::backslash(b'\''), + '\0' => EscapeDebug::backslash(ascii::Char::Digit0), + '\t' => EscapeDebug::backslash(ascii::Char::SmallT), + '\r' => EscapeDebug::backslash(ascii::Char::SmallR), + '\n' => EscapeDebug::backslash(ascii::Char::SmallN), + '\\' => EscapeDebug::backslash(ascii::Char::ReverseSolidus), + '\"' if args.escape_double_quote => EscapeDebug::backslash(ascii::Char::QuotationMark), + '\'' if args.escape_single_quote => EscapeDebug::backslash(ascii::Char::Apostrophe), _ if args.escape_grapheme_extended && self.is_grapheme_extended() => { EscapeDebug::from_unicode(self.escape_unicode()) } @@ -503,11 +503,11 @@ impl char { #[inline] pub fn escape_default(self) -> EscapeDefault { match self { - '\t' => EscapeDefault::backslash(b't'), - '\r' => EscapeDefault::backslash(b'r'), - '\n' => EscapeDefault::backslash(b'n'), - '\\' | '\'' | '"' => EscapeDefault::backslash(self as u8), - '\x20'..='\x7e' => EscapeDefault::printable(self as u8), + '\t' => EscapeDefault::backslash(ascii::Char::SmallT), + '\r' => EscapeDefault::backslash(ascii::Char::SmallR), + '\n' => EscapeDefault::backslash(ascii::Char::SmallN), + '\\' | '\'' | '"' => EscapeDefault::backslash(self.as_ascii().unwrap()), + '\x20'..='\x7e' => EscapeDefault::printable(self.as_ascii().unwrap()), _ => EscapeDefault::from_unicode(self.escape_unicode()), } } diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index e186db7052c..5c42912874c 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -38,6 +38,7 @@ pub use self::methods::encode_utf16_raw; #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] pub use self::methods::encode_utf8_raw; +use crate::ascii; use crate::error::Error; use crate::escape; use crate::fmt::{self, Write}; @@ -152,7 +153,7 @@ pub struct EscapeUnicode(escape::EscapeIterInner<10>); impl EscapeUnicode { fn new(chr: char) -> Self { - let mut data = [0; 10]; + let mut data = [ascii::Char::Null; 10]; let range = escape::escape_unicode_into(&mut data, chr); Self(escape::EscapeIterInner::new(data, range)) } @@ -218,14 +219,14 @@ impl fmt::Display for EscapeUnicode { pub struct EscapeDefault(escape::EscapeIterInner<10>); impl EscapeDefault { - fn printable(chr: u8) -> Self { - let data = [chr, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - Self(escape::EscapeIterInner::new(data, 0..1)) + fn printable(chr: ascii::Char) -> Self { + let data = [chr]; + Self(escape::EscapeIterInner::from_array(data)) } - fn backslash(chr: u8) -> Self { - let data = [b'\\', chr, 0, 0, 0, 0, 0, 0, 0, 0]; - Self(escape::EscapeIterInner::new(data, 0..2)) + fn backslash(chr: ascii::Char) -> Self { + let data = [ascii::Char::ReverseSolidus, chr]; + Self(escape::EscapeIterInner::from_array(data)) } fn from_unicode(esc: EscapeUnicode) -> Self { @@ -307,9 +308,9 @@ impl EscapeDebug { Self(EscapeDebugInner::Char(chr)) } - fn backslash(chr: u8) -> Self { - let data = [b'\\', chr, 0, 0, 0, 0, 0, 0, 0, 0]; - let iter = escape::EscapeIterInner::new(data, 0..2); + fn backslash(chr: ascii::Char) -> Self { + let data = [ascii::Char::ReverseSolidus, chr]; + let iter = escape::EscapeIterInner::from_array(data); Self(EscapeDebugInner::Bytes(iter)) } @@ -318,7 +319,7 @@ impl EscapeDebug { } fn clear(&mut self) { - let bytes = escape::EscapeIterInner::new([0; 10], 0..0); + let bytes = escape::EscapeIterInner::from_array([]); self.0 = EscapeDebugInner::Bytes(bytes); } } diff --git a/library/core/src/escape.rs b/library/core/src/escape.rs index 20ac3cf027f..3d471419bb8 100644 --- a/library/core/src/escape.rs +++ b/library/core/src/escape.rs @@ -1,34 +1,41 @@ //! Helper code for character escaping. +use crate::ascii; use crate::num::NonZeroUsize; use crate::ops::Range; -const HEX_DIGITS: [u8; 16] = *b"0123456789abcdef"; +const HEX_DIGITS: [ascii::Char; 16] = *b"0123456789abcdef".as_ascii().unwrap(); /// Escapes a byte into provided buffer; returns length of escaped /// representation. -pub(crate) fn escape_ascii_into(output: &mut [u8; 4], byte: u8) -> Range<u8> { +pub(crate) fn escape_ascii_into(output: &mut [ascii::Char; 4], byte: u8) -> Range<u8> { + #[inline] + fn backslash(a: ascii::Char) -> ([ascii::Char; 4], u8) { + ([ascii::Char::ReverseSolidus, a, ascii::Char::Null, ascii::Char::Null], 2) + } + let (data, len) = match byte { - b'\t' => ([b'\\', b't', 0, 0], 2), - b'\r' => ([b'\\', b'r', 0, 0], 2), - b'\n' => ([b'\\', b'n', 0, 0], 2), - b'\\' => ([b'\\', b'\\', 0, 0], 2), - b'\'' => ([b'\\', b'\'', 0, 0], 2), - b'"' => ([b'\\', b'"', 0, 0], 2), - b'\x20'..=b'\x7e' => ([byte, 0, 0, 0], 1), - _ => { + b'\t' => backslash(ascii::Char::SmallT), + b'\r' => backslash(ascii::Char::SmallR), + b'\n' => backslash(ascii::Char::SmallN), + b'\\' => backslash(ascii::Char::ReverseSolidus), + b'\'' => backslash(ascii::Char::Apostrophe), + b'\"' => backslash(ascii::Char::QuotationMark), + _ => if let Some(a) = byte.as_ascii() && !byte.is_ascii_control() { + ([a, ascii::Char::Null, ascii::Char::Null, ascii::Char::Null], 1) + } else { let hi = HEX_DIGITS[usize::from(byte >> 4)]; let lo = HEX_DIGITS[usize::from(byte & 0xf)]; - ([b'\\', b'x', hi, lo], 4) + ([ascii::Char::ReverseSolidus, ascii::Char::SmallX, hi, lo], 4) } }; *output = data; - 0..(len as u8) + 0..len } /// Escapes a character into provided buffer using `\u{NNNN}` representation. -pub(crate) fn escape_unicode_into(output: &mut [u8; 10], ch: char) -> Range<u8> { - output[9] = b'}'; +pub(crate) fn escape_unicode_into(output: &mut [ascii::Char; 10], ch: char) -> Range<u8> { + output[9] = ascii::Char::RightCurlyBracket; let ch = ch as u32; output[3] = HEX_DIGITS[((ch >> 20) & 15) as usize]; @@ -41,7 +48,8 @@ pub(crate) fn escape_unicode_into(output: &mut [u8; 10], ch: char) -> Range<u8> // or-ing 1 ensures that for ch==0 the code computes that one digit should // be printed. let start = (ch | 1).leading_zeros() as usize / 4 - 2; - output[start..start + 3].copy_from_slice(b"\\u{"); + const UNICODE_ESCAPE_PREFIX: &[ascii::Char; 3] = b"\\u{".as_ascii().unwrap(); + output[start..][..3].copy_from_slice(UNICODE_ESCAPE_PREFIX); (start as u8)..10 } @@ -52,29 +60,34 @@ pub(crate) fn escape_unicode_into(output: &mut [u8; 10], ch: char) -> Range<u8> /// limited to u8 to reduce size of the structure. #[derive(Clone, Debug)] pub(crate) struct EscapeIterInner<const N: usize> { - // Invariant: data[alive] is all ASCII. - pub(crate) data: [u8; N], + // The element type ensures this is always ASCII, and thus also valid UTF-8. + pub(crate) data: [ascii::Char; N], // Invariant: alive.start <= alive.end <= N. pub(crate) alive: Range<u8>, } impl<const N: usize> EscapeIterInner<N> { - pub fn new(data: [u8; N], alive: Range<u8>) -> Self { + pub fn new(data: [ascii::Char; N], alive: Range<u8>) -> Self { const { assert!(N < 256) }; debug_assert!(alive.start <= alive.end && usize::from(alive.end) <= N, "{alive:?}"); - let this = Self { data, alive }; - debug_assert!(this.as_bytes().is_ascii(), "Expected ASCII, got {:?}", this.as_bytes()); - this + Self { data, alive } + } + + pub fn from_array<const M: usize>(array: [ascii::Char; M]) -> Self { + const { assert!(M <= N) }; + + let mut data = [ascii::Char::Null; N]; + data[..M].copy_from_slice(&array); + Self::new(data, 0..M as u8) } - fn as_bytes(&self) -> &[u8] { + pub fn as_ascii(&self) -> &[ascii::Char] { &self.data[usize::from(self.alive.start)..usize::from(self.alive.end)] } pub fn as_str(&self) -> &str { - // SAFETY: self.data[self.alive] is all ASCII characters. - unsafe { crate::str::from_utf8_unchecked(self.as_bytes()) } + self.as_ascii().as_str() } pub fn len(&self) -> usize { @@ -82,11 +95,11 @@ impl<const N: usize> EscapeIterInner<N> { } pub fn next(&mut self) -> Option<u8> { - self.alive.next().map(|i| self.data[usize::from(i)]) + self.alive.next().map(|i| self.data[usize::from(i)].as_u8()) } pub fn next_back(&mut self) -> Option<u8> { - self.alive.next_back().map(|i| self.data[usize::from(i)]) + self.alive.next_back().map(|i| self.data[usize::from(i)].as_u8()) } pub fn advance_by(&mut self, n: usize) -> Result<(), NonZeroUsize> { diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs index 07b11814f96..201bacb28c7 100644 --- a/library/core/src/ffi/c_str.rs +++ b/library/core/src/ffi/c_str.rs @@ -517,8 +517,6 @@ impl CStr { /// # Examples /// /// ``` - /// #![feature(cstr_is_empty)] - /// /// use std::ffi::CStr; /// # use std::ffi::FromBytesWithNulError; /// @@ -533,7 +531,8 @@ impl CStr { /// # } /// ``` #[inline] - #[unstable(feature = "cstr_is_empty", issue = "102444")] + #[stable(feature = "cstr_is_empty", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "cstr_is_empty", since = "CURRENT_RUSTC_VERSION")] pub const fn is_empty(&self) -> bool { // SAFETY: We know there is at least one byte; for empty strings it // is the NUL terminator. diff --git a/library/core/src/ffi/mod.rs b/library/core/src/ffi/mod.rs index b85894259f1..b73abbbaca7 100644 --- a/library/core/src/ffi/mod.rs +++ b/library/core/src/ffi/mod.rs @@ -203,7 +203,7 @@ mod c_long_definition { // be UB. #[doc = include_str!("c_void.md")] #[cfg_attr(not(bootstrap), lang = "c_void")] -#[repr(u8)] +#[cfg_attr(not(doc), repr(u8))] // work around https://github.com/rust-lang/rust/issues/90435 #[stable(feature = "core_c_void", since = "1.30.0")] pub enum c_void { #[unstable( @@ -244,7 +244,7 @@ impl fmt::Debug for c_void { target_os = "uefi", windows, ))] -#[repr(transparent)] +#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 #[unstable( feature = "c_variadic", reason = "the `c_variadic` feature has not been properly tested on \ @@ -296,7 +296,7 @@ impl<'f> fmt::Debug for VaListImpl<'f> { not(target_os = "uefi"), not(windows), ))] -#[repr(C)] +#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 #[derive(Debug)] #[unstable( feature = "c_variadic", @@ -316,7 +316,7 @@ pub struct VaListImpl<'f> { /// PowerPC ABI implementation of a `va_list`. #[cfg(all(target_arch = "powerpc", not(target_os = "uefi"), not(windows)))] -#[repr(C)] +#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 #[derive(Debug)] #[unstable( feature = "c_variadic", @@ -336,7 +336,7 @@ pub struct VaListImpl<'f> { /// s390x ABI implementation of a `va_list`. #[cfg(target_arch = "s390x")] -#[repr(C)] +#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 #[derive(Debug)] #[unstable( feature = "c_variadic", @@ -355,7 +355,7 @@ pub struct VaListImpl<'f> { /// x86_64 ABI implementation of a `va_list`. #[cfg(all(target_arch = "x86_64", not(target_os = "uefi"), not(windows)))] -#[repr(C)] +#[cfg_attr(not(doc), repr(C))] // work around https://github.com/rust-lang/rust/issues/66401 #[derive(Debug)] #[unstable( feature = "c_variadic", @@ -373,7 +373,7 @@ pub struct VaListImpl<'f> { } /// A wrapper for a `va_list` -#[repr(transparent)] +#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 #[derive(Debug)] #[unstable( feature = "c_variadic", diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 89d5fac30d3..3bbf5d8770b 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -45,7 +45,8 @@ where &mut buf, &mut parts, ); - fmt.pad_formatted_parts(&formatted) + // SAFETY: `to_exact_fixed_str` and `format_exact` produce only ASCII characters. + unsafe { fmt.pad_formatted_parts(&formatted) } } // Don't inline this so callers that call both this and the above won't wind @@ -71,7 +72,8 @@ where &mut buf, &mut parts, ); - fmt.pad_formatted_parts(&formatted) + // SAFETY: `to_shortest_str` and `format_shortest` produce only ASCII characters. + unsafe { fmt.pad_formatted_parts(&formatted) } } fn float_to_decimal_display<T>(fmt: &mut Formatter<'_>, num: &T) -> Result @@ -116,7 +118,8 @@ where &mut buf, &mut parts, ); - fmt.pad_formatted_parts(&formatted) + // SAFETY: `to_exact_exp_str` and `format_exact` produce only ASCII characters. + unsafe { fmt.pad_formatted_parts(&formatted) } } // Don't inline this so callers that call both this and the above won't wind @@ -143,7 +146,8 @@ where &mut buf, &mut parts, ); - fmt.pad_formatted_parts(&formatted) + // SAFETY: `to_shortest_exp_str` and `format_shortest` produce only ASCII characters. + unsafe { fmt.pad_formatted_parts(&formatted) } } // Common code of floating point LowerExp and UpperExp. diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index bac2f31878b..1786b309c5b 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -1415,7 +1415,11 @@ impl<'a> Formatter<'a> { /// Takes the formatted parts and applies the padding. /// Assumes that the caller already has rendered the parts with required precision, /// so that `self.precision` can be ignored. - fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { + /// + /// # Safety + /// + /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8. + unsafe fn pad_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { if let Some(mut width) = self.width { // for the sign-aware zero padding, we render the sign first and // behave as if we had no sign from the beginning. @@ -1438,10 +1442,14 @@ impl<'a> Formatter<'a> { let len = formatted.len(); let ret = if width <= len { // no padding - self.write_formatted_parts(&formatted) + // SAFETY: Per the precondition. + unsafe { self.write_formatted_parts(&formatted) } } else { let post_padding = self.padding(width - len, Alignment::Right)?; - self.write_formatted_parts(&formatted)?; + // SAFETY: Per the precondition. + unsafe { + self.write_formatted_parts(&formatted)?; + } post_padding.write(self) }; self.fill = old_fill; @@ -1449,20 +1457,20 @@ impl<'a> Formatter<'a> { ret } else { // this is the common case and we take a shortcut - self.write_formatted_parts(formatted) + // SAFETY: Per the precondition. + unsafe { self.write_formatted_parts(formatted) } } } - fn write_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { - fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result { + /// # Safety + /// + /// Any `numfmt::Part::Copy` parts in `formatted` must contain valid UTF-8. + unsafe fn write_formatted_parts(&mut self, formatted: &numfmt::Formatted<'_>) -> Result { + unsafe fn write_bytes(buf: &mut dyn Write, s: &[u8]) -> Result { // SAFETY: This is used for `numfmt::Part::Num` and `numfmt::Part::Copy`. // It's safe to use for `numfmt::Part::Num` since every char `c` is between - // `b'0'` and `b'9'`, which means `s` is valid UTF-8. - // It's also probably safe in practice to use for `numfmt::Part::Copy(buf)` - // since `buf` should be plain ASCII, but it's possible for someone to pass - // in a bad value for `buf` into `numfmt::to_shortest_str` since it is a - // public function. - // FIXME: Determine whether this could result in UB. + // `b'0'` and `b'9'`, which means `s` is valid UTF-8. It's safe to use for + // `numfmt::Part::Copy` due to this function's precondition. buf.write_str(unsafe { str::from_utf8_unchecked(s) }) } @@ -1489,11 +1497,15 @@ impl<'a> Formatter<'a> { *c = b'0' + (v % 10) as u8; v /= 10; } - write_bytes(self.buf, &s[..len])?; + // SAFETY: Per the precondition. + unsafe { + write_bytes(self.buf, &s[..len])?; + } } - numfmt::Part::Copy(buf) => { + // SAFETY: Per the precondition. + numfmt::Part::Copy(buf) => unsafe { write_bytes(self.buf, buf)?; - } + }, } } Ok(()) diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index d8365ae9bf9..4f42f73ebba 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -52,8 +52,12 @@ impl_int! { i8 i16 i32 i64 i128 isize } impl_uint! { u8 u16 u32 u64 u128 usize } /// A type that represents a specific radix +/// +/// # Safety +/// +/// `digit` must return an ASCII character. #[doc(hidden)] -trait GenericRadix: Sized { +unsafe trait GenericRadix: Sized { /// The number of digits. const BASE: u8; @@ -129,7 +133,7 @@ struct UpperHex; macro_rules! radix { ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => { - impl GenericRadix for $T { + unsafe impl GenericRadix for $T { const BASE: u8 = $base; const PREFIX: &'static str = $prefix; fn digit(x: u8) -> u8 { @@ -407,7 +411,7 @@ macro_rules! impl_Exp { let parts = &[ numfmt::Part::Copy(buf_slice), numfmt::Part::Zero(added_precision), - numfmt::Part::Copy(exp_slice) + numfmt::Part::Copy(exp_slice), ]; let sign = if !is_nonnegative { "-" @@ -416,8 +420,9 @@ macro_rules! impl_Exp { } else { "" }; - let formatted = numfmt::Formatted{sign, parts}; - f.pad_formatted_parts(&formatted) + let formatted = numfmt::Formatted { sign, parts }; + // SAFETY: `buf_slice` and `exp_slice` contain only ASCII characters. + unsafe { f.pad_formatted_parts(&formatted) } } $( diff --git a/library/core/src/future/join.rs b/library/core/src/future/join.rs index 35f0dea062e..3f35179ddc2 100644 --- a/library/core/src/future/join.rs +++ b/library/core/src/future/join.rs @@ -4,7 +4,7 @@ use crate::cell::UnsafeCell; use crate::future::{poll_fn, Future}; use crate::mem; use crate::pin::Pin; -use crate::task::{Context, Poll}; +use crate::task::{ready, Context, Poll}; /// Polls multiple futures simultaneously, returning a tuple /// of all results once complete. @@ -118,7 +118,7 @@ macro join_internal { fut }) }; - // Despite how tempting it may be to `let () = fut.poll(cx).ready()?;` + // Despite how tempting it may be to `let () = ready!(fut.poll(cx));` // doing so would defeat the point of `join!`: to start polling eagerly all // of the futures, to allow parallelizing the waits. done &= fut.poll(cx).is_ready(); @@ -180,7 +180,7 @@ impl<F: Future> Future for MaybeDone<F> { // Do not mix match ergonomics with unsafe. match *self.as_mut().get_unchecked_mut() { MaybeDone::Future(ref mut f) => { - let val = Pin::new_unchecked(f).poll(cx).ready()?; + let val = ready!(Pin::new_unchecked(f).poll(cx)); self.set(Self::Done(val)); } MaybeDone::Done(_) => {} diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 19f8b944c1f..5944a0de1a4 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -228,7 +228,7 @@ //! //! - Operands implicitly convert to `Use` rvalues. //! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue. -//! - [`Discriminant`] and [`Len`] have associated functions. +//! - [`Discriminant`], [`Len`], and [`CopyForDeref`] have associated functions. //! - Unary and binary operations use their normal Rust syntax - `a * b`, `!c`, etc. //! - The binary operation `Offset` can be created via [`Offset`]. //! - Checked binary operations are represented by wrapping the associated binop in [`Checked`]. @@ -279,6 +279,7 @@ define!("mir_storage_dead", fn StorageDead<T>(local: T)); define!("mir_deinit", fn Deinit<T>(place: T)); define!("mir_checked", fn Checked<T>(binop: T) -> (T, bool)); define!("mir_len", fn Len<T>(place: T) -> usize); +define!("mir_copy_for_deref", fn CopyForDeref<T>(place: T) -> T); define!("mir_retag", fn Retag<T>(place: T)); define!("mir_move", fn Move<T>(place: T) -> T); define!("mir_static", fn Static<T>(s: T) -> &'static T); diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs index a0afaa326ad..723657b9e43 100644 --- a/library/core/src/iter/adapters/filter.rs +++ b/library/core/src/iter/adapters/filter.rs @@ -1,6 +1,9 @@ use crate::fmt; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; use crate::ops::Try; +use core::array; +use core::mem::{ManuallyDrop, MaybeUninit}; +use core::ops::ControlFlow; /// An iterator that filters the elements of `iter` with `predicate`. /// @@ -57,6 +60,58 @@ where } #[inline] + fn next_chunk<const N: usize>( + &mut self, + ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>> { + let mut array: [MaybeUninit<Self::Item>; N] = MaybeUninit::uninit_array(); + + struct Guard<'a, T> { + array: &'a mut [MaybeUninit<T>], + initialized: usize, + } + + impl<T> Drop for Guard<'_, T> { + #[inline] + fn drop(&mut self) { + if const { crate::mem::needs_drop::<T>() } { + // SAFETY: self.initialized is always <= N, which also is the length of the array. + unsafe { + core::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut( + self.array.get_unchecked_mut(..self.initialized), + )); + } + } + } + } + + let mut guard = Guard { array: &mut array, initialized: 0 }; + + let result = self.iter.try_for_each(|element| { + let idx = guard.initialized; + guard.initialized = idx + (self.predicate)(&element) as usize; + + // SAFETY: Loop conditions ensure the index is in bounds. + unsafe { guard.array.get_unchecked_mut(idx) }.write(element); + + if guard.initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } + }); + + let guard = ManuallyDrop::new(guard); + + match result { + ControlFlow::Break(()) => { + // SAFETY: The loop above is only explicitly broken when the array has been fully initialized + Ok(unsafe { MaybeUninit::array_assume_init(array) }) + } + ControlFlow::Continue(()) => { + let initialized = guard.initialized; + // SAFETY: The range is in bounds since the loop breaks when reaching N elements. + Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) }) + } + } + } + + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { let (_, upper) = self.iter.size_hint(); (0, upper) // can't know a lower bound, due to the predicate diff --git a/library/core/src/iter/adapters/filter_map.rs b/library/core/src/iter/adapters/filter_map.rs index 6bdf53f7fc9..693479977db 100644 --- a/library/core/src/iter/adapters/filter_map.rs +++ b/library/core/src/iter/adapters/filter_map.rs @@ -1,6 +1,7 @@ -use crate::fmt; use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable}; +use crate::mem::{ManuallyDrop, MaybeUninit}; use crate::ops::{ControlFlow, Try}; +use crate::{array, fmt}; /// An iterator that uses `f` to both filter and map elements from `iter`. /// @@ -62,6 +63,65 @@ where } #[inline] + fn next_chunk<const N: usize>( + &mut self, + ) -> Result<[Self::Item; N], array::IntoIter<Self::Item, N>> { + let mut array: [MaybeUninit<Self::Item>; N] = MaybeUninit::uninit_array(); + + struct Guard<'a, T> { + array: &'a mut [MaybeUninit<T>], + initialized: usize, + } + + impl<T> Drop for Guard<'_, T> { + #[inline] + fn drop(&mut self) { + if const { crate::mem::needs_drop::<T>() } { + // SAFETY: self.initialized is always <= N, which also is the length of the array. + unsafe { + core::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut( + self.array.get_unchecked_mut(..self.initialized), + )); + } + } + } + } + + let mut guard = Guard { array: &mut array, initialized: 0 }; + + let result = self.iter.try_for_each(|element| { + let idx = guard.initialized; + let val = (self.f)(element); + guard.initialized = idx + val.is_some() as usize; + + // SAFETY: Loop conditions ensure the index is in bounds. + + unsafe { + let opt_payload_at = core::intrinsics::option_payload_ptr(&val); + let dst = guard.array.as_mut_ptr().add(idx); + crate::ptr::copy_nonoverlapping(opt_payload_at.cast(), dst, 1); + crate::mem::forget(val); + }; + + if guard.initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } + }); + + let guard = ManuallyDrop::new(guard); + + match result { + ControlFlow::Break(()) => { + // SAFETY: The loop above is only explicitly broken when the array has been fully initialized + Ok(unsafe { MaybeUninit::array_assume_init(array) }) + } + ControlFlow::Continue(()) => { + let initialized = guard.initialized; + // SAFETY: The range is in bounds since the loop breaks when reaching N elements. + Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) }) + } + } + } + + #[inline] fn size_hint(&self) -> (usize, Option<usize>) { let (_, upper) = self.iter.size_hint(); (0, upper) // can't know a lower bound, due to the predicate diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 520ec9abcf0..2568aaf34f3 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -310,6 +310,7 @@ where /// Real logic of both `Flatten` and `FlatMap` which simply delegate to /// this type. #[derive(Clone, Debug)] +#[unstable(feature = "trusted_len", issue = "37572")] struct FlattenCompat<I, U> { iter: Fuse<I>, frontiter: Option<U>, @@ -463,6 +464,7 @@ where } } +#[unstable(feature = "trusted_len", issue = "37572")] impl<I, U> Iterator for FlattenCompat<I, U> where I: Iterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>, @@ -577,6 +579,7 @@ where } } +#[unstable(feature = "trusted_len", issue = "37572")] impl<I, U> DoubleEndedIterator for FlattenCompat<I, U> where I: DoubleEndedIterator<Item: IntoIterator<IntoIter = U, Item = U::Item>>, @@ -646,6 +649,7 @@ where } } +#[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<const N: usize, I, T> TrustedLen for FlattenCompat<I, <[T; N] as IntoIterator>::IntoIter> where @@ -653,6 +657,7 @@ where { } +#[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, const N: usize, I, T> TrustedLen for FlattenCompat<I, <&'a [T; N] as IntoIterator>::IntoIter> where @@ -660,6 +665,7 @@ where { } +#[unstable(feature = "trusted_len", issue = "37572")] unsafe impl<'a, const N: usize, I, T> TrustedLen for FlattenCompat<I, <&'a mut [T; N] as IntoIterator>::IntoIter> where diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 76b3a32880d..0675e56358f 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -95,6 +95,16 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( + _Self = "&[{A}]", + message = "a slice of type `{Self}` cannot be built since we need to store the elements somewhere", + label = "try explicitly collecting into a `Vec<{A}>`", + ), + on( + all(A = "{integer}", any(_Self = "&[{integral}]",)), + message = "a slice of type `{Self}` cannot be built since we need to store the elements somewhere", + label = "try explicitly collecting into a `Vec<{A}>`", + ), + on( _Self = "[{A}]", message = "a slice of type `{Self}` cannot be built since `{Self}` has no definite size", label = "try explicitly collecting into a `Vec<{A}>`", diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 26c51e84035..6c419eb16f3 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -133,6 +133,7 @@ #![feature(const_maybe_uninit_assume_init)] #![feature(const_maybe_uninit_uninit_array)] #![feature(const_nonnull_new)] +#![feature(const_num_midpoint)] #![feature(const_option)] #![feature(const_option_ext)] #![feature(const_pin)] @@ -215,6 +216,7 @@ #![feature(intra_doc_pointers)] #![feature(intrinsics)] #![feature(lang_items)] +#![feature(let_chains)] #![feature(link_llvm_intrinsics)] #![feature(macro_metavar_expr)] #![feature(min_specialization)] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 97f9d01e016..8dab8d1a692 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -43,27 +43,17 @@ use crate::hash::Hasher; /// ``` #[unstable(feature = "internal_impls_macro", issue = "none")] macro marker_impls { - ( $(#[$($meta:tt)*])* $Trait:ident for $( $({$($bounds:tt)*})? $T:ty ),+ $(,)?) => { - // This inner macro is needed because... idk macros are weird. - // It allows repeating `meta` on all impls. - #[unstable(feature = "internal_impls_macro", issue = "none")] - macro _impl { - ( $$({$$($$bounds_:tt)*})? $$T_:ty ) => { - $(#[$($meta)*])* impl<$$($$($$bounds_)*)?> $Trait for $$T_ {} - } - } - $( _impl! { $({$($bounds)*})? $T } )+ + ( $(#[$($meta:tt)*])* $Trait:ident for $({$($bounds:tt)*})? $T:ty $(, $($rest:tt)*)? ) => { + $(#[$($meta)*])* impl< $($($bounds)*)? > $Trait for $T {} + marker_impls! { $(#[$($meta)*])* $Trait for $($($rest)*)? } }, - ( $(#[$($meta:tt)*])* unsafe $Trait:ident for $( $({$($bounds:tt)*})? $T:ty ),+ $(,)?) => { - #[unstable(feature = "internal_impls_macro", issue = "none")] - macro _impl { - ( $$({$$($$bounds_:tt)*})? $$T_:ty ) => { - $(#[$($meta)*])* unsafe impl<$$($$($$bounds_)*)?> $Trait for $$T_ {} - } - } - - $( _impl! { $({$($bounds)*})? $T } )+ + ( $(#[$($meta:tt)*])* $Trait:ident for ) => {}, + + ( $(#[$($meta:tt)*])* unsafe $Trait:ident for $({$($bounds:tt)*})? $T:ty $(, $($rest:tt)*)? ) => { + $(#[$($meta)*])* unsafe impl< $($($bounds)*)? > $Trait for $T {} + marker_impls! { $(#[$($meta)*])* unsafe $Trait for $($($rest)*)? } }, + ( $(#[$($meta:tt)*])* unsafe $Trait:ident for ) => {}, } /// Types that can be transferred across thread boundaries. @@ -695,7 +685,7 @@ impl<T: ?Sized> !Sync for *mut T {} /// } /// ``` /// -/// This also in turn requires the annotation `T: 'a`, indicating +/// This also in turn infers the lifetime bound `T: 'a`, indicating /// that any references in `T` are valid over the lifetime `'a`. /// /// When initializing a `Slice` you simply provide the value @@ -766,16 +756,11 @@ impl<T: ?Sized> !Sync for *mut T {} /// /// ## Ownership and the drop check /// -/// Adding a field of type `PhantomData<T>` indicates that your -/// type owns data of type `T`. This in turn implies that when your -/// type is dropped, it may drop one or more instances of the type -/// `T`. This has bearing on the Rust compiler's [drop check] -/// analysis. +/// The exact interaction of `PhantomData` with drop check **may change in the future**. /// -/// If your struct does not in fact *own* the data of type `T`, it is -/// better to use a reference type, like `PhantomData<&'a T>` -/// (ideally) or `PhantomData<*const T>` (if no lifetime applies), so -/// as not to indicate ownership. +/// Currently, adding a field of type `PhantomData<T>` indicates that your type *owns* data of type +/// `T` in very rare circumstances. This in turn has effects on the Rust compiler's [drop check] +/// analysis. For the exact rules, see the [drop check] documentation. /// /// ## Layout /// @@ -783,7 +768,7 @@ impl<T: ?Sized> !Sync for *mut T {} /// * `size_of::<PhantomData<T>>() == 0` /// * `align_of::<PhantomData<T>>() == 1` /// -/// [drop check]: ../../nomicon/dropck.html +/// [drop check]: Drop#drop-check #[lang = "phantom_data"] #[stable(feature = "rust1", since = "1.0.0")] pub struct PhantomData<T: ?Sized>; @@ -991,6 +976,14 @@ pub trait PointerLike {} #[rustc_on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] pub trait ConstParamTy: StructuralEq {} +/// Derive macro generating an impl of the trait `ConstParamTy`. +#[rustc_builtin_macro] +#[unstable(feature = "adt_const_params", issue = "95174")] +#[cfg(not(bootstrap))] +pub macro ConstParamTy($item:item) { + /* compiler built-in */ +} + // FIXME(generic_const_parameter_types): handle `ty::FnDef`/`ty::Closure` // FIXME(generic_const_parameter_types): handle `ty::Tuple` marker_impls! { diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 4913a6de918..afbfd6d362d 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -968,6 +968,7 @@ pub const fn replace<T>(dest: &mut T, src: T) -> T { /// Integers and other types implementing [`Copy`] are unaffected by `drop`. /// /// ``` +/// # #![cfg_attr(not(bootstrap), allow(dropping_copy_types))] /// #[derive(Copy, Clone)] /// struct Foo(u8); /// diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs index 1c6819b547d..4a035ad61e1 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -940,6 +940,42 @@ impl f32 { } } + /// Calculates the middle point of `self` and `rhs`. + /// + /// This returns NaN when *either* argument is NaN or if a combination of + /// +inf and -inf is provided as arguments. + /// + /// # Examples + /// + /// ``` + /// #![feature(num_midpoint)] + /// assert_eq!(1f32.midpoint(4.0), 2.5); + /// assert_eq!((-5.5f32).midpoint(8.0), 1.25); + /// ``` + #[unstable(feature = "num_midpoint", issue = "110840")] + pub fn midpoint(self, other: f32) -> f32 { + const LO: f32 = f32::MIN_POSITIVE * 2.; + const HI: f32 = f32::MAX / 2.; + + let (a, b) = (self, other); + let abs_a = a.abs_private(); + let abs_b = b.abs_private(); + + if abs_a <= HI && abs_b <= HI { + // Overflow is impossible + (a + b) / 2. + } else if abs_a < LO { + // Not safe to halve a + a + (b / 2.) + } else if abs_b < LO { + // Not safe to halve b + (a / 2.) + b + } else { + // Not safe to halve a and b + (a / 2.) + (b / 2.) + } + } + /// Rounds toward zero and converts to any primitive integer type, /// assuming that the value is finite and fits in that type. /// diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 1e7387217cb..3aafc435f1e 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -951,6 +951,42 @@ impl f64 { } } + /// Calculates the middle point of `self` and `rhs`. + /// + /// This returns NaN when *either* argument is NaN or if a combination of + /// +inf and -inf is provided as arguments. + /// + /// # Examples + /// + /// ``` + /// #![feature(num_midpoint)] + /// assert_eq!(1f64.midpoint(4.0), 2.5); + /// assert_eq!((-5.5f64).midpoint(8.0), 1.25); + /// ``` + #[unstable(feature = "num_midpoint", issue = "110840")] + pub fn midpoint(self, other: f64) -> f64 { + const LO: f64 = f64::MIN_POSITIVE * 2.; + const HI: f64 = f64::MAX / 2.; + + let (a, b) = (self, other); + let abs_a = a.abs_private(); + let abs_b = b.abs_private(); + + if abs_a <= HI && abs_b <= HI { + // Overflow is impossible + (a + b) / 2. + } else if abs_a < LO { + // Not safe to halve a + a + (b / 2.) + } else if abs_b < LO { + // Not safe to halve b + (a / 2.) + b + } else { + // Not safe to halve a and b + (a / 2.) + (b / 2.) + } + } + /// Rounds toward zero and converts to any primitive integer type, /// assuming that the value is finite and fits in that type. /// diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 17715c9291f..1199d09b563 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2332,6 +2332,44 @@ macro_rules! int_impl { } } + /// Calculates the middle point of `self` and `rhs`. + /// + /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a + /// sufficiently-large signed integral type. This implies that the result is + /// always rounded towards negative infinity and that no overflow will ever occur. + /// + /// # Examples + /// + /// ``` + /// #![feature(num_midpoint)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(-1), -1);")] + #[doc = concat!("assert_eq!((-1", stringify!($SelfT), ").midpoint(0), -1);")] + /// ``` + #[unstable(feature = "num_midpoint", issue = "110840")] + #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] + #[rustc_allow_const_fn_unstable(const_num_midpoint)] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn midpoint(self, rhs: Self) -> Self { + const U: $UnsignedT = <$SelfT>::MIN.unsigned_abs(); + + // Map an $SelfT to an $UnsignedT + // ex: i8 [-128; 127] to [0; 255] + const fn map(a: $SelfT) -> $UnsignedT { + (a as $UnsignedT) ^ U + } + + // Map an $UnsignedT to an $SelfT + // ex: u8 [0; 255] to [-128; 127] + const fn demap(a: $UnsignedT) -> $SelfT { + (a ^ U) as $SelfT + } + + demap(<$UnsignedT>::midpoint(map(self), map(rhs))) + } + /// Returns the logarithm of the number with respect to an arbitrary base, /// rounded down. /// diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 08444421dca..c9baa09f407 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -95,6 +95,57 @@ depending on the target pointer size. }; } +macro_rules! midpoint_impl { + ($SelfT:ty, unsigned) => { + /// Calculates the middle point of `self` and `rhs`. + /// + /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a + /// sufficiently-large signed integral type. This implies that the result is + /// always rounded towards negative infinity and that no overflow will ever occur. + /// + /// # Examples + /// + /// ``` + /// #![feature(num_midpoint)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")] + /// ``` + #[unstable(feature = "num_midpoint", issue = "110840")] + #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn midpoint(self, rhs: $SelfT) -> $SelfT { + // Use the well known branchless algorthim from Hacker's Delight to compute + // `(a + b) / 2` without overflowing: `((a ^ b) >> 1) + (a & b)`. + ((self ^ rhs) >> 1) + (self & rhs) + } + }; + ($SelfT:ty, $WideT:ty, unsigned) => { + /// Calculates the middle point of `self` and `rhs`. + /// + /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a + /// sufficiently-large signed integral type. This implies that the result is + /// always rounded towards negative infinity and that no overflow will ever occur. + /// + /// # Examples + /// + /// ``` + /// #![feature(num_midpoint)] + #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".midpoint(4), 2);")] + #[doc = concat!("assert_eq!(1", stringify!($SelfT), ".midpoint(4), 2);")] + /// ``` + #[unstable(feature = "num_midpoint", issue = "110840")] + #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn midpoint(self, rhs: $SelfT) -> $SelfT { + ((self as $WideT + rhs as $WideT) / 2) as $SelfT + } + }; +} + macro_rules! widening_impl { ($SelfT:ty, $WideT:ty, $BITS:literal, unsigned) => { /// Calculates the complete product `self * rhs` without the possibility to overflow. @@ -455,6 +506,7 @@ impl u8 { bound_condition = "", } widening_impl! { u8, u16, 8, unsigned } + midpoint_impl! { u8, u16, unsigned } /// Checks if the value is within the ASCII range. /// @@ -1066,6 +1118,7 @@ impl u16 { bound_condition = "", } widening_impl! { u16, u32, 16, unsigned } + midpoint_impl! { u16, u32, unsigned } /// Checks if the value is a Unicode surrogate code point, which are disallowed values for [`char`]. /// @@ -1114,6 +1167,7 @@ impl u32 { bound_condition = "", } widening_impl! { u32, u64, 32, unsigned } + midpoint_impl! { u32, u64, unsigned } } impl u64 { @@ -1137,6 +1191,7 @@ impl u64 { bound_condition = "", } widening_impl! { u64, u128, 64, unsigned } + midpoint_impl! { u64, u128, unsigned } } impl u128 { @@ -1161,6 +1216,7 @@ impl u128 { from_xe_bytes_doc = "", bound_condition = "", } + midpoint_impl! { u128, unsigned } } #[cfg(target_pointer_width = "16")] @@ -1185,6 +1241,7 @@ impl usize { bound_condition = " on 16-bit targets", } widening_impl! { usize, u32, 16, unsigned } + midpoint_impl! { usize, u32, unsigned } } #[cfg(target_pointer_width = "32")] @@ -1209,6 +1266,7 @@ impl usize { bound_condition = " on 32-bit targets", } widening_impl! { usize, u64, 32, unsigned } + midpoint_impl! { usize, u64, unsigned } } #[cfg(target_pointer_width = "64")] @@ -1233,6 +1291,7 @@ impl usize { bound_condition = " on 64-bit targets", } widening_impl! { usize, u128, 64, unsigned } + midpoint_impl! { usize, u128, unsigned } } impl usize { diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 74a325b89d4..38a1c42d9e8 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -493,6 +493,43 @@ macro_rules! nonzero_unsigned_operations { pub const fn ilog10(self) -> u32 { super::int_log10::$Int(self.0) } + + /// Calculates the middle point of `self` and `rhs`. + /// + /// `midpoint(a, b)` is `(a + b) >> 1` as if it were performed in a + /// sufficiently-large signed integral type. This implies that the result is + /// always rounded towards negative infinity and that no overflow will ever occur. + /// + /// # Examples + /// + /// ``` + /// #![feature(num_midpoint)] + #[doc = concat!("# use std::num::", stringify!($Ty), ";")] + /// + /// # fn main() { test().unwrap(); } + /// # fn test() -> Option<()> { + #[doc = concat!("let one = ", stringify!($Ty), "::new(1)?;")] + #[doc = concat!("let two = ", stringify!($Ty), "::new(2)?;")] + #[doc = concat!("let four = ", stringify!($Ty), "::new(4)?;")] + /// + /// assert_eq!(one.midpoint(four), two); + /// assert_eq!(four.midpoint(one), two); + /// # Some(()) + /// # } + /// ``` + #[unstable(feature = "num_midpoint", issue = "110840")] + #[rustc_const_unstable(feature = "const_num_midpoint", issue = "110840")] + #[rustc_allow_const_fn_unstable(const_num_midpoint)] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn midpoint(self, rhs: Self) -> Self { + // SAFETY: The only way to get `0` with midpoint is to have two opposite or + // near opposite numbers: (-5, 5), (0, 1), (0, 0) which is impossible because + // of the unsignedness of this number and also because $Ty is guaranteed to + // never being 0. + unsafe { $Ty::new_unchecked(self.get().midpoint(rhs.get())) } + } } )+ } @@ -719,8 +756,6 @@ macro_rules! nonzero_signed_operations { /// # Example /// /// ``` - /// #![feature(nonzero_negation_ops)] - /// #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { @@ -734,7 +769,8 @@ macro_rules! nonzero_signed_operations { /// ``` #[must_use] #[inline] - #[unstable(feature = "nonzero_negation_ops", issue = "102443")] + #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] pub const fn is_positive(self) -> bool { self.get().is_positive() } @@ -745,8 +781,6 @@ macro_rules! nonzero_signed_operations { /// # Example /// /// ``` - /// #![feature(nonzero_negation_ops)] - /// #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { @@ -760,7 +794,8 @@ macro_rules! nonzero_signed_operations { /// ``` #[must_use] #[inline] - #[unstable(feature = "nonzero_negation_ops", issue = "102443")] + #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] pub const fn is_negative(self) -> bool { self.get().is_negative() } @@ -770,8 +805,6 @@ macro_rules! nonzero_signed_operations { /// # Example /// /// ``` - /// #![feature(nonzero_negation_ops)] - /// #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { @@ -786,7 +819,8 @@ macro_rules! nonzero_signed_operations { /// # } /// ``` #[inline] - #[unstable(feature = "nonzero_negation_ops", issue = "102443")] + #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] pub const fn checked_neg(self) -> Option<$Ty> { if let Some(result) = self.get().checked_neg() { // SAFETY: negation of nonzero cannot yield zero values. @@ -803,8 +837,6 @@ macro_rules! nonzero_signed_operations { /// # Example /// /// ``` - /// #![feature(nonzero_negation_ops)] - /// #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { @@ -819,7 +851,8 @@ macro_rules! nonzero_signed_operations { /// # } /// ``` #[inline] - #[unstable(feature = "nonzero_negation_ops", issue = "102443")] + #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] pub const fn overflowing_neg(self) -> ($Ty, bool) { let (result, overflow) = self.get().overflowing_neg(); // SAFETY: negation of nonzero cannot yield zero values. @@ -832,8 +865,6 @@ macro_rules! nonzero_signed_operations { /// # Example /// /// ``` - /// #![feature(nonzero_negation_ops)] - /// #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { @@ -853,7 +884,8 @@ macro_rules! nonzero_signed_operations { /// # } /// ``` #[inline] - #[unstable(feature = "nonzero_negation_ops", issue = "102443")] + #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] pub const fn saturating_neg(self) -> $Ty { if let Some(result) = self.checked_neg() { return result; @@ -870,8 +902,6 @@ macro_rules! nonzero_signed_operations { /// # Example /// /// ``` - /// #![feature(nonzero_negation_ops)] - /// #[doc = concat!("# use std::num::", stringify!($Ty), ";")] /// # fn main() { test().unwrap(); } /// # fn test() -> Option<()> { @@ -886,7 +916,8 @@ macro_rules! nonzero_signed_operations { /// # } /// ``` #[inline] - #[unstable(feature = "nonzero_negation_ops", issue = "102443")] + #[stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] + #[rustc_const_stable(feature = "nonzero_negation_ops", since = "CURRENT_RUSTC_VERSION")] pub const fn wrapping_neg(self) -> $Ty { let result = self.get().wrapping_neg(); // SAFETY: negation of nonzero cannot yield zero values. diff --git a/library/core/src/ops/drop.rs b/library/core/src/ops/drop.rs index a2c3d978cc4..9ebf426be95 100644 --- a/library/core/src/ops/drop.rs +++ b/library/core/src/ops/drop.rs @@ -132,6 +132,74 @@ /// are `Copy` get implicitly duplicated by the compiler, making it very /// hard to predict when, and how often destructors will be executed. As such, /// these types cannot have destructors. +/// +/// ## Drop check +/// +/// Dropping interacts with the borrow checker in subtle ways: when a type `T` is being implicitly +/// dropped as some variable of this type goes out of scope, the borrow checker needs to ensure that +/// calling `T`'s destructor at this moment is safe. In particular, it also needs to be safe to +/// recursively drop all the fields of `T`. For example, it is crucial that code like the following +/// is being rejected: +/// +/// ```compile_fail,E0597 +/// use std::cell::Cell; +/// +/// struct S<'a>(Cell<Option<&'a S<'a>>>, Box<i32>); +/// impl Drop for S<'_> { +/// fn drop(&mut self) { +/// if let Some(r) = self.0.get() { +/// // Print the contents of the `Box` in `r`. +/// println!("{}", r.1); +/// } +/// } +/// } +/// +/// fn main() { +/// // Set up two `S` that point to each other. +/// let s1 = S(Cell::new(None), Box::new(42)); +/// let s2 = S(Cell::new(Some(&s1)), Box::new(42)); +/// s1.0.set(Some(&s2)); +/// // Now they both get dropped. But whichever is the 2nd one +/// // to be dropped will access the `Box` in the first one, +/// // which is a use-after-free! +/// } +/// ``` +/// +/// The Nomicon discusses the need for [drop check in more detail][drop check]. +/// +/// To reject such code, the "drop check" analysis determines which types and lifetimes need to +/// still be live when `T` gets dropped. The exact details of this analysis are not yet +/// stably guaranteed and **subject to change**. Currently, the analysis works as follows: +/// - If `T` has no drop glue, then trivially nothing is required to be live. This is the case if +/// neither `T` nor any of its (recursive) fields have a destructor (`impl Drop`). [`PhantomData`] +/// and [`ManuallyDrop`] are considered to never have a destructor, no matter their field type. +/// - If `T` has drop glue, then, for all types `U` that are *owned* by any field of `T`, +/// recursively add the types and lifetimes that need to be live when `U` gets dropped. The set of +/// owned types is determined by recursively traversing `T`: +/// - Recursively descend through `PhantomData`, `Box`, tuples, and arrays (including arrays of +/// length 0). +/// - Stop at reference and raw pointer types as well as function pointers and function items; +/// they do not own anything. +/// - Stop at non-composite types (type parameters that remain generic in the current context and +/// base types such as integers and `bool`); these types are owned. +/// - When hitting an ADT with `impl Drop`, stop there; this type is owned. +/// - When hitting an ADT without `impl Drop`, recursively descend to its fields. (For an `enum`, +/// consider all fields of all variants.) +/// - Furthermore, if `T` implements `Drop`, then all generic (lifetime and type) parameters of `T` +/// must be live. +/// +/// In the above example, the last clause implies that `'a` must be live when `S<'a>` is dropped, +/// and hence the example is rejected. If we remove the `impl Drop`, the liveness requirement +/// disappears and the example is accepted. +/// +/// There exists an unstable way for a type to opt-out of the last clause; this is called "drop +/// check eyepatch" or `may_dangle`. For more details on this nightly-only feature, see the +/// [discussion in the Nomicon][nomicon]. +/// +/// [`ManuallyDrop`]: crate::mem::ManuallyDrop +/// [`PhantomData`]: crate::marker::PhantomData +/// [drop check]: ../../nomicon/dropck.html +/// [nomicon]: ../../nomicon/phantom-data.html#an-exception-the-special-case-of-the-standard-library-and-its-unstable-may_dangle #[lang = "drop"] #[stable(feature = "rust1", since = "1.0.0")] #[const_trait] diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 8338a5d7e5a..20be60d3535 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -28,16 +28,18 @@ pub macro panic_2015 { $crate::panicking::panic($msg) ), // Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint. - ($msg:expr $(,)?) => ( - $crate::panicking::panic_str($msg) - ), + ($msg:expr $(,)?) => ({ + $crate::panicking::panic_str($msg); + }), // Special-case the single-argument case for const_panic. - ("{}", $arg:expr $(,)?) => ( - $crate::panicking::panic_display(&$arg) - ), - ($fmt:expr, $($arg:tt)+) => ( - $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+)) - ), + ("{}", $arg:expr $(,)?) => ({ + $crate::panicking::panic_display(&$arg); + }), + ($fmt:expr, $($arg:tt)+) => ({ + // Semicolon to prevent temporaries inside the formatting machinery from + // being considered alive in the caller after the panic_fmt call. + $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+)); + }), } #[doc(hidden)] @@ -50,12 +52,14 @@ pub macro panic_2021 { $crate::panicking::panic("explicit panic") ), // Special-case the single-argument case for const_panic. - ("{}", $arg:expr $(,)?) => ( - $crate::panicking::panic_display(&$arg) - ), - ($($t:tt)+) => ( - $crate::panicking::panic_fmt($crate::const_format_args!($($t)+)) - ), + ("{}", $arg:expr $(,)?) => ({ + $crate::panicking::panic_display(&$arg); + }), + ($($t:tt)+) => ({ + // Semicolon to prevent temporaries inside the formatting machinery from + // being considered alive in the caller after the panic_fmt call. + $crate::panicking::panic_fmt($crate::const_format_args!($($t)+)); + }), } #[doc(hidden)] @@ -69,9 +73,9 @@ pub macro unreachable_2015 { ), // Use of `unreachable_display` for non_fmt_panic lint. // NOTE: the message ("internal error ...") is embedded directly in unreachable_display - ($msg:expr $(,)?) => ( - $crate::panicking::unreachable_display(&$msg) - ), + ($msg:expr $(,)?) => ({ + $crate::panicking::unreachable_display(&$msg); + }), ($fmt:expr, $($arg:tt)*) => ( $crate::panic!($crate::concat!("internal error: entered unreachable code: ", $fmt), $($arg)*) ), diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs index 06fbe083ca1..5576adde84b 100644 --- a/library/core/src/panic/panic_info.rs +++ b/library/core/src/panic/panic_info.rs @@ -134,7 +134,7 @@ impl<'a> PanicInfo<'a> { /// whose ABI does not support unwinding. /// /// It is safe for a panic handler to unwind even when this function returns - /// true, however this will simply cause the panic handler to be called + /// false, however this will simply cause the panic handler to be called /// again. #[must_use] #[unstable(feature = "panic_can_unwind", issue = "92988")] diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index c4b89a63019..6b319b4355c 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -393,6 +393,8 @@ use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn, Receiver}; /// value in place, preventing the value referenced by that pointer from being moved /// unless it implements [`Unpin`]. /// +/// `Pin<P>` is guaranteed to have the same memory layout and ABI as `P`. +/// /// *See the [`pin` module] documentation for an explanation of pinning.* /// /// [`pin` module]: self diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs index 67fcef0f466..5369fe0a9a9 100644 --- a/library/core/src/slice/iter.rs +++ b/library/core/src/slice/iter.rs @@ -90,8 +90,6 @@ impl<'a, T> Iter<'a, T> { let ptr = slice.as_ptr(); // SAFETY: Similar to `IterMut::new`. unsafe { - assume(!ptr.is_null()); - let end = if T::IS_ZST { invalid(slice.len()) } else { ptr.add(slice.len()) }; Self { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: PhantomData } @@ -228,8 +226,6 @@ impl<'a, T> IterMut<'a, T> { // See the `next_unchecked!` and `is_empty!` macros as well as the // `post_inc_start` method for more information. unsafe { - assume(!ptr.is_null()); - let end = if T::IS_ZST { invalid_mut(slice.len()) } else { ptr.add(slice.len()) }; Self { ptr: NonNull::new_unchecked(ptr), end, _marker: PhantomData } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index c2e9ba273a5..5ece1b78c03 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -995,7 +995,7 @@ impl<T> [T] { #[unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] - pub unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] { + pub const unsafe fn as_chunks_unchecked<const N: usize>(&self) -> &[[T; N]] { let this = self; // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { @@ -1043,7 +1043,7 @@ impl<T> [T] { #[inline] #[track_caller] #[must_use] - pub fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T]) { + pub const fn as_chunks<const N: usize>(&self) -> (&[[T; N]], &[T]) { assert!(N != 0, "chunk size must be non-zero"); let len = self.len() / N; let (multiple_of_n, remainder) = self.split_at(len * N); @@ -1075,7 +1075,7 @@ impl<T> [T] { #[inline] #[track_caller] #[must_use] - pub fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]]) { + pub const fn as_rchunks<const N: usize>(&self) -> (&[T], &[[T; N]]) { assert!(N != 0, "chunk size must be non-zero"); let len = self.len() / N; let (remainder, multiple_of_n) = self.split_at(self.len() - len * N); @@ -1152,7 +1152,7 @@ impl<T> [T] { #[unstable(feature = "slice_as_chunks", issue = "74985")] #[inline] #[must_use] - pub unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] { + pub const unsafe fn as_chunks_unchecked_mut<const N: usize>(&mut self) -> &mut [[T; N]] { let this = &*self; // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length let new_len = unsafe { @@ -1195,7 +1195,7 @@ impl<T> [T] { #[inline] #[track_caller] #[must_use] - pub fn as_chunks_mut<const N: usize>(&mut self) -> (&mut [[T; N]], &mut [T]) { + pub const fn as_chunks_mut<const N: usize>(&mut self) -> (&mut [[T; N]], &mut [T]) { assert!(N != 0, "chunk size must be non-zero"); let len = self.len() / N; let (multiple_of_n, remainder) = self.split_at_mut(len * N); @@ -1233,7 +1233,7 @@ impl<T> [T] { #[inline] #[track_caller] #[must_use] - pub fn as_rchunks_mut<const N: usize>(&mut self) -> (&mut [T], &mut [[T; N]]) { + pub const fn as_rchunks_mut<const N: usize>(&mut self) -> (&mut [T], &mut [[T; N]]) { assert!(N != 0, "chunk size must be non-zero"); let len = self.len() / N; let (remainder, multiple_of_n) = self.split_at_mut(self.len() - len * N); @@ -1595,7 +1595,8 @@ impl<T> [T] { /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_slice_split_at_not_mut", issue = "101158")] + #[rustc_const_stable(feature = "const_slice_split_at_not_mut", since = "CURRENT_RUSTC_VERSION")] + #[rustc_allow_const_fn_unstable(slice_split_at_unchecked)] #[inline] #[track_caller] #[must_use] diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index e6e3b55efa9..eb8595ca90d 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -1085,12 +1085,12 @@ where // SAFETY: left and right must be valid and part of v same for out. unsafe { - let to_copy = if is_less(&*right, &**left) { - get_and_increment(&mut right) - } else { - get_and_increment(left) - }; - ptr::copy_nonoverlapping(to_copy, get_and_increment(out), 1); + let is_l = is_less(&*right, &**left); + let to_copy = if is_l { right } else { *left }; + ptr::copy_nonoverlapping(to_copy, *out, 1); + *out = out.add(1); + right = right.add(is_l as usize); + *left = left.add(!is_l as usize); } } } else { @@ -1113,32 +1113,18 @@ where // SAFETY: left and right must be valid and part of v same for out. unsafe { - let to_copy = if is_less(&*right.sub(1), &*left.sub(1)) { - decrement_and_get(left) - } else { - decrement_and_get(right) - }; - ptr::copy_nonoverlapping(to_copy, decrement_and_get(&mut out), 1); + let is_l = is_less(&*right.sub(1), &*left.sub(1)); + *left = left.sub(is_l as usize); + *right = right.sub(!is_l as usize); + let to_copy = if is_l { *left } else { *right }; + out = out.sub(1); + ptr::copy_nonoverlapping(to_copy, out, 1); } } } // Finally, `hole` gets dropped. If the shorter run was not fully consumed, whatever remains of // it will now be copied into the hole in `v`. - unsafe fn get_and_increment<T>(ptr: &mut *mut T) -> *mut T { - let old = *ptr; - - // SAFETY: ptr.add(1) must still be a valid pointer and part of `v`. - *ptr = unsafe { ptr.add(1) }; - old - } - - unsafe fn decrement_and_get<T>(ptr: &mut *mut T) -> *mut T { - // SAFETY: ptr.sub(1) must still be a valid pointer and part of `v`. - *ptr = unsafe { ptr.sub(1) }; - *ptr - } - // When dropped, copies the range `start..end` into `dest..`. struct MergeHole<T> { start: *mut T, diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index e3a464a1c51..91ee2903aab 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -791,8 +791,8 @@ pub struct CharArrayRefSearcher<'a, 'b, const N: usize>( /// # Examples /// /// ``` -/// assert_eq!("Hello world".find(['l', 'l']), Some(2)); -/// assert_eq!("Hello world".find(['l', 'l']), Some(2)); +/// assert_eq!("Hello world".find(['o', 'l']), Some(2)); +/// assert_eq!("Hello world".find(['h', 'w']), Some(6)); /// ``` impl<'a, const N: usize> Pattern<'a> for [char; N] { pattern_methods!(CharArraySearcher<'a, N>, MultiCharEqPattern, CharArraySearcher); @@ -811,8 +811,8 @@ unsafe impl<'a, const N: usize> ReverseSearcher<'a> for CharArraySearcher<'a, N> /// # Examples /// /// ``` -/// assert_eq!("Hello world".find(&['l', 'l']), Some(2)); -/// assert_eq!("Hello world".find(&['l', 'l']), Some(2)); +/// assert_eq!("Hello world".find(&['o', 'l']), Some(2)); +/// assert_eq!("Hello world".find(&['h', 'w']), Some(6)); /// ``` impl<'a, 'b, const N: usize> Pattern<'a> for &'b [char; N] { pattern_methods!(CharArrayRefSearcher<'a, 'b, N>, MultiCharEqPattern, CharArrayRefSearcher); diff --git a/library/core/src/task/mod.rs b/library/core/src/task/mod.rs index c5f89b9a2c6..3f0080e3832 100644 --- a/library/core/src/task/mod.rs +++ b/library/core/src/task/mod.rs @@ -13,5 +13,3 @@ pub use self::wake::{Context, RawWaker, RawWakerVTable, Waker}; mod ready; #[stable(feature = "ready_macro", since = "1.64.0")] pub use ready::ready; -#[unstable(feature = "poll_ready", issue = "89780")] -pub use ready::Ready; diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 168516263f1..0a0f702f6fb 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -3,7 +3,6 @@ use crate::convert; use crate::ops::{self, ControlFlow}; use crate::result::Result; -use crate::task::Ready; /// Indicates whether a value is available or if the current task has been /// scheduled to receive a wakeup instead. @@ -95,38 +94,6 @@ impl<T> Poll<T> { pub const fn is_pending(&self) -> bool { !self.is_ready() } - - /// Extracts the successful type of a [`Poll<T>`]. - /// - /// When combined with the `?` operator, this function will - /// propagate any [`Poll::Pending`] values to the caller, and - /// extract the `T` from [`Poll::Ready`]. - /// - /// # Examples - /// - /// ```rust - /// #![feature(poll_ready)] - /// - /// use std::task::{Context, Poll}; - /// use std::future::{self, Future}; - /// use std::pin::Pin; - /// - /// pub fn do_poll(cx: &mut Context<'_>) -> Poll<()> { - /// let mut fut = future::ready(42); - /// let fut = Pin::new(&mut fut); - /// - /// let num = fut.poll(cx).ready()?; - /// # drop(num); - /// // ... use num - /// - /// Poll::Ready(()) - /// } - /// ``` - #[inline] - #[unstable(feature = "poll_ready", issue = "89780")] - pub fn ready(self) -> Ready<T> { - Ready(self) - } } impl<T, E> Poll<Result<T, E>> { diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index b1daf545fbe..495d72fd14b 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -1,8 +1,3 @@ -use core::convert; -use core::fmt; -use core::ops::{ControlFlow, FromResidual, Try}; -use core::task::Poll; - /// Extracts the successful type of a [`Poll<T>`]. /// /// This macro bakes in propagation of [`Pending`] signals by returning early. @@ -22,7 +17,7 @@ use core::task::Poll; /// let fut = Pin::new(&mut fut); /// /// let num = ready!(fut.poll(cx)); -/// # drop(num); +/// # let _ = num; /// // ... use num /// /// Poll::Ready(()) @@ -44,7 +39,7 @@ use core::task::Poll; /// Poll::Ready(t) => t, /// Poll::Pending => return Poll::Pending, /// }; -/// # drop(num); +/// # let _ = num; // to silence unused warning /// # // ... use num /// # /// # Poll::Ready(()) @@ -60,55 +55,3 @@ pub macro ready($e:expr) { } } } - -/// Extracts the successful type of a [`Poll<T>`]. -/// -/// See [`Poll::ready`] for details. -#[unstable(feature = "poll_ready", issue = "89780")] -pub struct Ready<T>(pub(crate) Poll<T>); - -#[unstable(feature = "poll_ready", issue = "89780")] -impl<T> Try for Ready<T> { - type Output = T; - type Residual = Ready<convert::Infallible>; - - #[inline] - fn from_output(output: Self::Output) -> Self { - Ready(Poll::Ready(output)) - } - - #[inline] - fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { - match self.0 { - Poll::Ready(v) => ControlFlow::Continue(v), - Poll::Pending => ControlFlow::Break(Ready(Poll::Pending)), - } - } -} - -#[unstable(feature = "poll_ready", issue = "89780")] -impl<T> FromResidual for Ready<T> { - #[inline] - fn from_residual(residual: Ready<convert::Infallible>) -> Self { - match residual.0 { - Poll::Pending => Ready(Poll::Pending), - } - } -} - -#[unstable(feature = "poll_ready", issue = "89780")] -impl<T> FromResidual<Ready<convert::Infallible>> for Poll<T> { - #[inline] - fn from_residual(residual: Ready<convert::Infallible>) -> Self { - match residual.0 { - Poll::Pending => Poll::Pending, - } - } -} - -#[unstable(feature = "poll_ready", issue = "89780")] -impl<T> fmt::Debug for Ready<T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Ready").finish() - } -} diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 808825326ae..7043ab5ff2b 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -232,7 +232,7 @@ impl fmt::Debug for Context<'_> { /// /// [`Future::poll()`]: core::future::Future::poll /// [`Poll::Pending`]: core::task::Poll::Pending -#[repr(transparent)] +#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/66401 #[stable(feature = "futures_api", since = "1.36.0")] pub struct Waker { waker: RawWaker, diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 3c49d1705e5..3933e328951 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -53,6 +53,7 @@ #![feature(maybe_uninit_uninit_array_transpose)] #![feature(min_specialization)] #![feature(numfmt)] +#![feature(num_midpoint)] #![feature(step_trait)] #![feature(str_internals)] #![feature(std_internals)] diff --git a/library/core/tests/mem.rs b/library/core/tests/mem.rs index 7f033816901..aee9c89b595 100644 --- a/library/core/tests/mem.rs +++ b/library/core/tests/mem.rs @@ -386,6 +386,26 @@ fn offset_of() { // Layout of tuples is unstable assert!(offset_of!((u8, u16), 0) <= size_of::<(u8, u16)>() - 1); assert!(offset_of!((u8, u16), 1) <= size_of::<(u8, u16)>() - 2); + + #[repr(C)] + struct Generic<T> { + x: u8, + y: u32, + z: T + } + + trait Trait {} + + // Ensure that this type of generics works + fn offs_of_z<T>() -> usize { + offset_of!(Generic<T>, z) + } + + assert_eq!(offset_of!(Generic<u8>, z), 8); + assert_eq!(offs_of_z::<u8>(), 8); + + // Ensure that it works with the implicit lifetime in `Box<dyn Trait + '_>`. + assert_eq!(offset_of!(Generic<Box<dyn Trait>>, z), 8); } #[test] diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 18c55e43aac..439bbe66997 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -364,6 +364,32 @@ macro_rules! int_module { assert_eq!((0 as $T).borrowing_sub($T::MIN, false), ($T::MIN, true)); assert_eq!((0 as $T).borrowing_sub($T::MIN, true), ($T::MAX, false)); } + + #[test] + fn test_midpoint() { + assert_eq!(<$T>::midpoint(1, 3), 2); + assert_eq!(<$T>::midpoint(3, 1), 2); + + assert_eq!(<$T>::midpoint(0, 0), 0); + assert_eq!(<$T>::midpoint(0, 2), 1); + assert_eq!(<$T>::midpoint(2, 0), 1); + assert_eq!(<$T>::midpoint(2, 2), 2); + + assert_eq!(<$T>::midpoint(1, 4), 2); + assert_eq!(<$T>::midpoint(4, 1), 2); + assert_eq!(<$T>::midpoint(3, 4), 3); + assert_eq!(<$T>::midpoint(4, 3), 3); + + assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), -1); + assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), -1); + assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); + assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); + + assert_eq!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); + assert_eq!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); + assert_eq!(<$T>::midpoint(<$T>::MAX, 6), <$T>::MAX / 2 + 3); + assert_eq!(<$T>::midpoint(6, <$T>::MAX), <$T>::MAX / 2 + 3); + } } }; } diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index 3e1f848ccfe..3f3659ba837 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -724,7 +724,7 @@ assume_usize_width! { } macro_rules! test_float { - ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => { + ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr, $min: expr, $max: expr, $min_pos: expr) => { mod $modname { #[test] fn min() { @@ -845,6 +845,38 @@ macro_rules! test_float { assert!(($nan as $fty).maximum($nan).is_nan()); } #[test] + fn midpoint() { + assert_eq!((0.5 as $fty).midpoint(0.5), 0.5); + assert_eq!((0.5 as $fty).midpoint(2.5), 1.5); + assert_eq!((3.0 as $fty).midpoint(4.0), 3.5); + assert_eq!((-3.0 as $fty).midpoint(4.0), 0.5); + assert_eq!((3.0 as $fty).midpoint(-4.0), -0.5); + assert_eq!((-3.0 as $fty).midpoint(-4.0), -3.5); + assert_eq!((0.0 as $fty).midpoint(0.0), 0.0); + assert_eq!((-0.0 as $fty).midpoint(-0.0), -0.0); + assert_eq!((-5.0 as $fty).midpoint(5.0), 0.0); + assert_eq!(($max as $fty).midpoint($min), 0.0); + assert_eq!(($min as $fty).midpoint($max), -0.0); + assert_eq!(($max as $fty).midpoint($min_pos), $max / 2.); + assert_eq!((-$max as $fty).midpoint($min_pos), -$max / 2.); + assert_eq!(($max as $fty).midpoint(-$min_pos), $max / 2.); + assert_eq!((-$max as $fty).midpoint(-$min_pos), -$max / 2.); + assert_eq!(($min_pos as $fty).midpoint($max), $max / 2.); + assert_eq!(($min_pos as $fty).midpoint(-$max), -$max / 2.); + assert_eq!((-$min_pos as $fty).midpoint($max), $max / 2.); + assert_eq!((-$min_pos as $fty).midpoint(-$max), -$max / 2.); + assert_eq!(($max as $fty).midpoint($max), $max); + assert_eq!(($min_pos as $fty).midpoint($min_pos), $min_pos); + assert_eq!((-$min_pos as $fty).midpoint(-$min_pos), -$min_pos); + assert_eq!(($max as $fty).midpoint(5.0), $max / 2.0 + 2.5); + assert_eq!(($max as $fty).midpoint(-5.0), $max / 2.0 - 2.5); + assert_eq!(($inf as $fty).midpoint($inf), $inf); + assert_eq!(($neginf as $fty).midpoint($neginf), $neginf); + assert!(($nan as $fty).midpoint(1.0).is_nan()); + assert!((1.0 as $fty).midpoint($nan).is_nan()); + assert!(($nan as $fty).midpoint($nan).is_nan()); + } + #[test] fn rem_euclid() { let a: $fty = 42.0; assert!($inf.rem_euclid(a).is_nan()); @@ -867,5 +899,23 @@ macro_rules! test_float { }; } -test_float!(f32, f32, f32::INFINITY, f32::NEG_INFINITY, f32::NAN); -test_float!(f64, f64, f64::INFINITY, f64::NEG_INFINITY, f64::NAN); +test_float!( + f32, + f32, + f32::INFINITY, + f32::NEG_INFINITY, + f32::NAN, + f32::MIN, + f32::MAX, + f32::MIN_POSITIVE +); +test_float!( + f64, + f64, + f64::INFINITY, + f64::NEG_INFINITY, + f64::NAN, + f64::MIN, + f64::MAX, + f64::MIN_POSITIVE +); diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index 15ae9f2324f..7d6203db0b9 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -252,6 +252,32 @@ macro_rules! uint_module { assert_eq!($T::MAX.borrowing_sub(0, true), ($T::MAX - 1, false)); assert_eq!($T::MAX.borrowing_sub($T::MAX, true), ($T::MAX, true)); } + + #[test] + fn test_midpoint() { + assert_eq!(<$T>::midpoint(1, 3), 2); + assert_eq!(<$T>::midpoint(3, 1), 2); + + assert_eq!(<$T>::midpoint(0, 0), 0); + assert_eq!(<$T>::midpoint(0, 2), 1); + assert_eq!(<$T>::midpoint(2, 0), 1); + assert_eq!(<$T>::midpoint(2, 2), 2); + + assert_eq!(<$T>::midpoint(1, 4), 2); + assert_eq!(<$T>::midpoint(4, 1), 2); + assert_eq!(<$T>::midpoint(3, 4), 3); + assert_eq!(<$T>::midpoint(4, 3), 3); + + assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2); + assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MIN), (<$T>::MAX - <$T>::MIN) / 2); + assert_eq!(<$T>::midpoint(<$T>::MIN, <$T>::MIN), <$T>::MIN); + assert_eq!(<$T>::midpoint(<$T>::MAX, <$T>::MAX), <$T>::MAX); + + assert_eq!(<$T>::midpoint(<$T>::MIN, 6), <$T>::MIN / 2 + 3); + assert_eq!(<$T>::midpoint(6, <$T>::MIN), <$T>::MIN / 2 + 3); + assert_eq!(<$T>::midpoint(<$T>::MAX, 6), (<$T>::MAX - <$T>::MIN) / 2 + 3); + assert_eq!(<$T>::midpoint(6, <$T>::MAX), (<$T>::MAX - <$T>::MIN) / 2 + 3); + } } }; } diff --git a/library/portable-simd/crates/core_simd/src/masks.rs b/library/portable-simd/crates/core_simd/src/masks.rs index e58df80fca8..e0f3c7beef6 100644 --- a/library/portable-simd/crates/core_simd/src/masks.rs +++ b/library/portable-simd/crates/core_simd/src/masks.rs @@ -88,7 +88,7 @@ impl_element! { isize } /// The layout of this type is unspecified, and may change between platforms /// and/or Rust versions, and code should not assume that it is equivalent to /// `[T; LANES]`. -#[repr(transparent)] +#[cfg_attr(not(doc), repr(transparent))] // work around https://github.com/rust-lang/rust/issues/90435 pub struct Mask<T, const LANES: usize>(mask_impl::Mask<T, LANES>) where T: MaskElement, diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index 6640c7fb162..89dfdfafdb1 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -15,6 +15,7 @@ use crate::ffi::OsString; use crate::fmt; use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; use crate::path::{Path, PathBuf}; +use crate::sealed::Sealed; use crate::sys::fs as fs_imp; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; use crate::time::SystemTime; @@ -1391,6 +1392,16 @@ impl FileTimes { } } +impl AsInnerMut<fs_imp::FileTimes> for FileTimes { + fn as_inner_mut(&mut self) -> &mut fs_imp::FileTimes { + &mut self.0 + } +} + +// For implementing OS extension traits in `std::os` +#[unstable(feature = "file_set_times", issue = "98245")] +impl Sealed for FileTimes {} + impl Permissions { /// Returns `true` if these permissions describe a readonly (unwritable) file. /// @@ -1946,7 +1957,7 @@ pub fn rename<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> io::Result<()> /// On success, the total number of bytes copied is returned and it is equal to /// the length of the `to` file as reported by `metadata`. /// -/// If you’re wanting to copy the contents of one file to another and you’re +/// If you want to copy the contents of one file to another and you’re /// working with [`File`]s, see the [`io::copy()`] function. /// /// # Platform-specific behavior diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs index a8a0b9f122d..e2480bcbbc7 100644 --- a/library/std/src/fs/tests.rs +++ b/library/std/src/fs/tests.rs @@ -1,7 +1,7 @@ use crate::io::prelude::*; use crate::env; -use crate::fs::{self, File, OpenOptions}; +use crate::fs::{self, File, FileTimes, OpenOptions}; use crate::io::{BorrowedBuf, ErrorKind, SeekFrom}; use crate::mem::MaybeUninit; use crate::path::Path; @@ -9,7 +9,7 @@ use crate::str; use crate::sync::Arc; use crate::sys_common::io::test::{tmpdir, TempDir}; use crate::thread; -use crate::time::{Duration, Instant}; +use crate::time::{Duration, Instant, SystemTime}; use rand::RngCore; @@ -1633,3 +1633,53 @@ fn rename_directory() { assert!(new_path.join("newdir").is_dir()); assert!(new_path.join("newdir/temp.txt").exists()); } + +#[test] +fn test_file_times() { + #[cfg(target_os = "ios")] + use crate::os::ios::fs::FileTimesExt; + #[cfg(target_os = "macos")] + use crate::os::macos::fs::FileTimesExt; + #[cfg(target_os = "watchos")] + use crate::os::watchos::fs::FileTimesExt; + #[cfg(windows)] + use crate::os::windows::fs::FileTimesExt; + + let tmp = tmpdir(); + let file = File::create(tmp.join("foo")).unwrap(); + let mut times = FileTimes::new(); + let accessed = SystemTime::UNIX_EPOCH + Duration::from_secs(12345); + let modified = SystemTime::UNIX_EPOCH + Duration::from_secs(54321); + times = times.set_accessed(accessed).set_modified(modified); + #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + let created = SystemTime::UNIX_EPOCH + Duration::from_secs(32123); + #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + { + times = times.set_created(created); + } + match file.set_times(times) { + // Allow unsupported errors on platforms which don't support setting times. + #[cfg(not(any( + windows, + all( + unix, + not(any( + target_os = "android", + target_os = "redox", + target_os = "espidf", + target_os = "horizon" + )) + ) + )))] + Err(e) if e.kind() == ErrorKind::Unsupported => return, + Err(e) => panic!("error setting file times: {e:?}"), + Ok(_) => {} + } + let metadata = file.metadata().unwrap(); + assert_eq!(metadata.accessed().unwrap(), accessed); + assert_eq!(metadata.modified().unwrap(), modified); + #[cfg(any(windows, target_os = "macos", target_os = "ios", target_os = "watchos"))] + { + assert_eq!(metadata.created().unwrap(), created); + } +} diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs index 38b98afffa1..1d9d93f5b64 100644 --- a/library/std/src/io/copy.rs +++ b/library/std/src/io/copy.rs @@ -10,7 +10,7 @@ use crate::mem::MaybeUninit; /// On success, the total number of bytes that were copied from /// `reader` to `writer` is returned. /// -/// If you’re wanting to copy the contents of one file to another and you’re +/// If you want to copy the contents of one file to another and you’re /// working with filesystem paths, see the [`fs::copy`] function. /// /// [`fs::copy`]: crate::fs::copy diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index 541e95d229b..141a18a42dd 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -756,6 +756,15 @@ impl TcpListener { /// ]; /// let listener = TcpListener::bind(&addrs[..]).unwrap(); /// ``` + /// + /// Creates a TCP listener bound to a port assigned by the operating system + /// at `127.0.0.1`. + /// + /// ```no_run + /// use std::net::TcpListener; + /// + /// let socket = TcpListener::bind("127.0.0.1:0").unwrap(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<TcpListener> { super::each_addr(addr, net_imp::TcpListener::bind).map(TcpListener) diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index 9628bcc5108..5ca4ed832f3 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -90,6 +90,15 @@ impl UdpSocket { /// ]; /// let socket = UdpSocket::bind(&addrs[..]).expect("couldn't bind to address"); /// ``` + /// + /// Creates a UDP socket bound to a port assigned by the operating system + /// at `127.0.0.1`. + /// + /// ```no_run + /// use std::net::UdpSocket; + /// + /// let socket = UdpSocket::bind("127.0.0.1:0").unwrap(); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<UdpSocket> { super::each_addr(addr, net_imp::UdpSocket::bind).map(UdpSocket) diff --git a/library/std/src/os/ios/fs.rs b/library/std/src/os/ios/fs.rs index 4a4637ce072..6d4d54b7c78 100644 --- a/library/std/src/os/ios/fs.rs +++ b/library/std/src/os/ios/fs.rs @@ -1,7 +1,9 @@ #![stable(feature = "metadata_ext", since = "1.1.0")] -use crate::fs::Metadata; -use crate::sys_common::AsInner; +use crate::fs::{self, Metadata}; +use crate::sealed::Sealed; +use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; +use crate::time::SystemTime; #[allow(deprecated)] use crate::os::ios::raw; @@ -140,3 +142,19 @@ impl MetadataExt for Metadata { self.as_inner().as_inner().st_lspare as u32 } } + +/// OS-specific extensions to [`fs::FileTimes`]. +#[unstable(feature = "file_set_times", issue = "98245")] +pub trait FileTimesExt: Sealed { + /// Set the creation time of a file. + #[unstable(feature = "file_set_times", issue = "98245")] + fn set_created(self, t: SystemTime) -> Self; +} + +#[unstable(feature = "file_set_times", issue = "98245")] +impl FileTimesExt for fs::FileTimes { + fn set_created(mut self, t: SystemTime) -> Self { + self.as_inner_mut().set_created(t.into_inner()); + self + } +} diff --git a/library/std/src/os/macos/fs.rs b/library/std/src/os/macos/fs.rs index 91915da6a43..fe82d03d869 100644 --- a/library/std/src/os/macos/fs.rs +++ b/library/std/src/os/macos/fs.rs @@ -1,7 +1,9 @@ #![stable(feature = "metadata_ext", since = "1.1.0")] -use crate::fs::Metadata; -use crate::sys_common::AsInner; +use crate::fs::{self, Metadata}; +use crate::sealed::Sealed; +use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; +use crate::time::SystemTime; #[allow(deprecated)] use crate::os::macos::raw; @@ -146,3 +148,19 @@ impl MetadataExt for Metadata { [qspare[0] as u64, qspare[1] as u64] } } + +/// OS-specific extensions to [`fs::FileTimes`]. +#[unstable(feature = "file_set_times", issue = "98245")] +pub trait FileTimesExt: Sealed { + /// Set the creation time of a file. + #[unstable(feature = "file_set_times", issue = "98245")] + fn set_created(self, t: SystemTime) -> Self; +} + +#[unstable(feature = "file_set_times", issue = "98245")] +impl FileTimesExt for fs::FileTimes { + fn set_created(mut self, t: SystemTime) -> Self { + self.as_inner_mut().set_created(t.into_inner()); + self + } +} diff --git a/library/std/src/os/watchos/fs.rs b/library/std/src/os/watchos/fs.rs index a14fe35a77c..2ecc4c68a96 100644 --- a/library/std/src/os/watchos/fs.rs +++ b/library/std/src/os/watchos/fs.rs @@ -1,7 +1,9 @@ #![stable(feature = "metadata_ext", since = "1.1.0")] -use crate::fs::Metadata; -use crate::sys_common::AsInner; +use crate::fs::{self, Metadata}; +use crate::sealed::Sealed; +use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; +use crate::time::SystemTime; #[allow(deprecated)] use crate::os::watchos::raw; @@ -140,3 +142,19 @@ impl MetadataExt for Metadata { self.as_inner().as_inner().st_lspare as u32 } } + +/// OS-specific extensions to [`fs::FileTimes`]. +#[unstable(feature = "file_set_times", issue = "98245")] +pub trait FileTimesExt: Sealed { + /// Set the creation time of a file. + #[unstable(feature = "file_set_times", issue = "98245")] + fn set_created(self, t: SystemTime) -> Self; +} + +#[unstable(feature = "file_set_times", issue = "98245")] +impl FileTimesExt for fs::FileTimes { + fn set_created(mut self, t: SystemTime) -> Self { + self.as_inner_mut().set_created(t.into_inner()); + self + } +} diff --git a/library/std/src/os/windows/fs.rs b/library/std/src/os/windows/fs.rs index a091f06dd53..94509e54796 100644 --- a/library/std/src/os/windows/fs.rs +++ b/library/std/src/os/windows/fs.rs @@ -9,7 +9,8 @@ use crate::io; use crate::path::Path; use crate::sealed::Sealed; use crate::sys; -use crate::sys_common::{AsInner, AsInnerMut}; +use crate::sys_common::{AsInner, AsInnerMut, IntoInner}; +use crate::time::SystemTime; /// Windows-specific extensions to [`fs::File`]. #[stable(feature = "file_offset", since = "1.15.0")] @@ -526,6 +527,22 @@ impl FileTypeExt for fs::FileType { } } +/// Windows-specific extensions to [`fs::FileTimes`]. +#[unstable(feature = "file_set_times", issue = "98245")] +pub trait FileTimesExt: Sealed { + /// Set the creation time of a file. + #[unstable(feature = "file_set_times", issue = "98245")] + fn set_created(self, t: SystemTime) -> Self; +} + +#[unstable(feature = "file_set_times", issue = "98245")] +impl FileTimesExt for fs::FileTimes { + fn set_created(mut self, t: SystemTime) -> Self { + self.as_inner_mut().set_created(t.into_inner()); + self + } +} + /// Creates a new symlink to a non-directory file on the filesystem. /// /// The `link` path will be a file symbolic link pointing to the `original` diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs index 280757a41a2..cbf8209a5ad 100644 --- a/library/std/src/os/windows/io/handle.rs +++ b/library/std/src/os/windows/io/handle.rs @@ -437,6 +437,42 @@ impl<T: AsHandle> AsHandle for &mut T { } } +#[stable(feature = "as_windows_ptrs", since = "CURRENT_RUSTC_VERSION")] +/// This impl allows implementing traits that require `AsHandle` on Arc. +/// ``` +/// # #[cfg(windows)] mod group_cfg { +/// # use std::os::windows::io::AsHandle; +/// use std::fs::File; +/// use std::sync::Arc; +/// +/// trait MyTrait: AsHandle {} +/// impl MyTrait for Arc<File> {} +/// impl MyTrait for Box<File> {} +/// # } +/// ``` +impl<T: AsHandle> AsHandle for crate::sync::Arc<T> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + (**self).as_handle() + } +} + +#[stable(feature = "as_windows_ptrs", since = "CURRENT_RUSTC_VERSION")] +impl<T: AsHandle> AsHandle for crate::rc::Rc<T> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + (**self).as_handle() + } +} + +#[stable(feature = "as_windows_ptrs", since = "CURRENT_RUSTC_VERSION")] +impl<T: AsHandle> AsHandle for Box<T> { + #[inline] + fn as_handle(&self) -> BorrowedHandle<'_> { + (**self).as_handle() + } +} + #[stable(feature = "io_safety", since = "1.63.0")] impl AsHandle for BorrowedHandle<'_> { #[inline] diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs index eb6097a89a6..0c90d55c024 100644 --- a/library/std/src/os/windows/io/socket.rs +++ b/library/std/src/os/windows/io/socket.rs @@ -254,6 +254,42 @@ impl<T: AsSocket> AsSocket for &mut T { } } +#[stable(feature = "as_windows_ptrs", since = "CURRENT_RUSTC_VERSION")] +/// This impl allows implementing traits that require `AsSocket` on Arc. +/// ``` +/// # #[cfg(windows)] mod group_cfg { +/// # use std::os::windows::io::AsSocket; +/// use std::net::UdpSocket; +/// use std::sync::Arc; +/// +/// trait MyTrait: AsSocket {} +/// impl MyTrait for Arc<UdpSocket> {} +/// impl MyTrait for Box<UdpSocket> {} +/// # } +/// ``` +impl<T: AsSocket> AsSocket for crate::sync::Arc<T> { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + (**self).as_socket() + } +} + +#[stable(feature = "as_windows_ptrs", since = "CURRENT_RUSTC_VERSION")] +impl<T: AsSocket> AsSocket for crate::rc::Rc<T> { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + (**self).as_socket() + } +} + +#[stable(feature = "as_windows_ptrs", since = "CURRENT_RUSTC_VERSION")] +impl<T: AsSocket> AsSocket for Box<T> { + #[inline] + fn as_socket(&self) -> BorrowedSocket<'_> { + (**self).as_socket() + } +} + #[stable(feature = "io_safety", since = "1.63.0")] impl AsSocket for BorrowedSocket<'_> { #[inline] diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 345d72ef867..69a6f3e6d5a 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -19,14 +19,16 @@ pub macro panic_2015 { $crate::rt::begin_panic("explicit panic") }), ($msg:expr $(,)?) => ({ - $crate::rt::begin_panic($msg) + $crate::rt::begin_panic($msg); }), // Special-case the single-argument case for const_panic. ("{}", $arg:expr $(,)?) => ({ - $crate::rt::panic_display(&$arg) + $crate::rt::panic_display(&$arg); }), ($fmt:expr, $($arg:tt)+) => ({ - $crate::rt::panic_fmt($crate::const_format_args!($fmt, $($arg)+)) + // Semicolon to prevent temporaries inside the formatting machinery from + // being considered alive in the caller after the panic_fmt call. + $crate::rt::panic_fmt($crate::const_format_args!($fmt, $($arg)+)); }), } diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index a46a29cbad6..6d59266b6f8 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -541,7 +541,7 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! { // Lazily, the first time this gets called, run the actual string formatting. self.string.get_or_insert_with(|| { let mut s = String::new(); - drop(s.write_fmt(*inner)); + let _err = s.write_fmt(*inner); s }) } diff --git a/library/std/src/path.rs b/library/std/src/path.rs index 43203c5824d..febdeb51463 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -733,8 +733,9 @@ impl<'a> Components<'a> { } } - // parse a given byte sequence into the corresponding path component - fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option<Component<'b>> { + // parse a given byte sequence following the OsStr encoding into the + // corresponding path component + unsafe fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option<Component<'b>> { match comp { b"." if self.prefix_verbatim() => Some(Component::CurDir), b"." => None, // . components are normalized away, except at @@ -754,7 +755,8 @@ impl<'a> Components<'a> { None => (0, self.path), Some(i) => (1, &self.path[..i]), }; - (comp.len() + extra, self.parse_single_component(comp)) + // SAFETY: `comp` is a valid substring, since it is split on a separator. + (comp.len() + extra, unsafe { self.parse_single_component(comp) }) } // parse a component from the right, saying how many bytes to consume to @@ -766,7 +768,8 @@ impl<'a> Components<'a> { None => (0, &self.path[start..]), Some(i) => (1, &self.path[start + i + 1..]), }; - (comp.len() + extra, self.parse_single_component(comp)) + // SAFETY: `comp` is a valid substring, since it is split on a separator. + (comp.len() + extra, unsafe { self.parse_single_component(comp) }) } // trim away repeated separators (i.e., empty components) on the left diff --git a/library/std/src/sync/mpmc/error.rs b/library/std/src/sync/mpmc/error.rs index 1b8a1f38797..33b2bff8534 100644 --- a/library/std/src/sync/mpmc/error.rs +++ b/library/std/src/sync/mpmc/error.rs @@ -35,7 +35,7 @@ impl<T> fmt::Display for SendTimeoutError<T> { } } -impl<T: Send> error::Error for SendTimeoutError<T> {} +impl<T> error::Error for SendTimeoutError<T> {} impl<T> From<SendError<T>> for SendTimeoutError<T> { fn from(err: SendError<T>) -> SendTimeoutError<T> { diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index 6e3c28f10bb..0e0c87d1c74 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -1124,7 +1124,7 @@ impl<T> fmt::Display for SendError<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Send> error::Error for SendError<T> { +impl<T> error::Error for SendError<T> { #[allow(deprecated)] fn description(&self) -> &str { "sending on a closed channel" @@ -1152,7 +1152,7 @@ impl<T> fmt::Display for TrySendError<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Send> error::Error for TrySendError<T> { +impl<T> error::Error for TrySendError<T> { #[allow(deprecated)] fn description(&self) -> &str { match *self { diff --git a/library/std/src/sys/sgx/waitqueue/mod.rs b/library/std/src/sys/sgx/waitqueue/mod.rs index 61bb11d9a6f..5e1d859ee99 100644 --- a/library/std/src/sys/sgx/waitqueue/mod.rs +++ b/library/std/src/sys/sgx/waitqueue/mod.rs @@ -202,12 +202,18 @@ impl WaitQueue { pub fn notify_one<T>( mut guard: SpinMutexGuard<'_, WaitVariable<T>>, ) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> { + // SAFETY: lifetime of the pop() return value is limited to the map + // closure (The closure return value is 'static). The underlying + // stack frame won't be freed until after the WaitGuard created below + // is dropped. unsafe { - if let Some(entry) = guard.queue.inner.pop() { + let tcs = guard.queue.inner.pop().map(|entry| -> Tcs { let mut entry_guard = entry.lock(); - let tcs = entry_guard.tcs; entry_guard.wake = true; - drop(entry); + entry_guard.tcs + }); + + if let Some(tcs) = tcs { Ok(WaitGuard { mutex_guard: Some(guard), notified_tcs: NotifiedTcs::Single(tcs) }) } else { Err(guard) @@ -223,6 +229,9 @@ impl WaitQueue { pub fn notify_all<T>( mut guard: SpinMutexGuard<'_, WaitVariable<T>>, ) -> Result<WaitGuard<'_, T>, SpinMutexGuard<'_, WaitVariable<T>>> { + // SAFETY: lifetime of the pop() return values are limited to the + // while loop body. The underlying stack frames won't be freed until + // after the WaitGuard created below is dropped. unsafe { let mut count = 0; while let Some(entry) = guard.queue.inner.pop() { @@ -230,6 +239,7 @@ impl WaitQueue { let mut entry_guard = entry.lock(); entry_guard.wake = true; } + if let Some(count) = NonZeroUsize::new(count) { Ok(WaitGuard { mutex_guard: Some(guard), notified_tcs: NotifiedTcs::All { count } }) } else { diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 22d2ae39713..09e9ae2720f 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -349,6 +349,8 @@ pub struct FilePermissions { pub struct FileTimes { accessed: Option<SystemTime>, modified: Option<SystemTime>, + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + created: Option<SystemTime>, } #[derive(Copy, Clone, Eq, Debug)] @@ -591,6 +593,11 @@ impl FileTimes { pub fn set_modified(&mut self, t: SystemTime) { self.modified = Some(t); } + + #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] + pub fn set_created(&mut self, t: SystemTime) { + self.created = Some(t); + } } impl FileType { @@ -1210,31 +1217,46 @@ impl File { // Redox doesn't appear to support `UTIME_OMIT`. // ESP-IDF and HorizonOS do not support `futimens` at all and the behavior for those OS is therefore // the same as for Redox. - drop(times); + let _ = times; Err(io::const_io_error!( io::ErrorKind::Unsupported, "setting file times not supported", )) - } else if #[cfg(any(target_os = "android", target_os = "macos"))] { + } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))] { + let mut buf = [mem::MaybeUninit::<libc::timespec>::uninit(); 3]; + let mut num_times = 0; + let mut attrlist: libc::attrlist = unsafe { mem::zeroed() }; + attrlist.bitmapcount = libc::ATTR_BIT_MAP_COUNT; + if times.created.is_some() { + buf[num_times].write(to_timespec(times.created)?); + num_times += 1; + attrlist.commonattr |= libc::ATTR_CMN_CRTIME; + } + if times.modified.is_some() { + buf[num_times].write(to_timespec(times.modified)?); + num_times += 1; + attrlist.commonattr |= libc::ATTR_CMN_MODTIME; + } + if times.accessed.is_some() { + buf[num_times].write(to_timespec(times.accessed)?); + num_times += 1; + attrlist.commonattr |= libc::ATTR_CMN_ACCTIME; + } + cvt(unsafe { libc::fsetattrlist( + self.as_raw_fd(), + (&attrlist as *const libc::attrlist).cast::<libc::c_void>().cast_mut(), + buf.as_ptr().cast::<libc::c_void>().cast_mut(), + num_times * mem::size_of::<libc::timespec>(), + 0 + ) })?; + Ok(()) + } else if #[cfg(target_os = "android")] { let times = [to_timespec(times.accessed)?, to_timespec(times.modified)?]; - // futimens requires macOS 10.13, and Android API level 19 + // futimens requires Android API level 19 cvt(unsafe { weak!(fn futimens(c_int, *const libc::timespec) -> c_int); match futimens.get() { Some(futimens) => futimens(self.as_raw_fd(), times.as_ptr()), - #[cfg(target_os = "macos")] - None => { - fn ts_to_tv(ts: &libc::timespec) -> libc::timeval { - libc::timeval { - tv_sec: ts.tv_sec, - tv_usec: (ts.tv_nsec / 1000) as _ - } - } - let timevals = [ts_to_tv(×[0]), ts_to_tv(×[1])]; - libc::futimes(self.as_raw_fd(), timevals.as_ptr()) - } - // futimes requires even newer Android. - #[cfg(target_os = "android")] None => return Err(io::const_io_error!( io::ErrorKind::Unsupported, "setting file times requires Android API level >= 19", diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs index ce427766d17..21a65bc25f3 100644 --- a/library/std/src/sys/windows/fs.rs +++ b/library/std/src/sys/windows/fs.rs @@ -88,8 +88,10 @@ pub struct FilePermissions { pub struct FileTimes { accessed: Option<c::FILETIME>, modified: Option<c::FILETIME>, + created: Option<c::FILETIME>, } -impl core::fmt::Debug for c::FILETIME { + +impl fmt::Debug for c::FILETIME { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let time = ((self.dwHighDateTime as u64) << 32) | self.dwLowDateTime as u64; f.debug_tuple("FILETIME").field(&time).finish() @@ -582,7 +584,10 @@ impl File { pub fn set_times(&self, times: FileTimes) -> io::Result<()> { let is_zero = |t: c::FILETIME| t.dwLowDateTime == 0 && t.dwHighDateTime == 0; - if times.accessed.map_or(false, is_zero) || times.modified.map_or(false, is_zero) { + if times.accessed.map_or(false, is_zero) + || times.modified.map_or(false, is_zero) + || times.created.map_or(false, is_zero) + { return Err(io::const_io_error!( io::ErrorKind::InvalidInput, "Cannot set file timestamp to 0", @@ -590,18 +595,23 @@ impl File { } let is_max = |t: c::FILETIME| t.dwLowDateTime == c::DWORD::MAX && t.dwHighDateTime == c::DWORD::MAX; - if times.accessed.map_or(false, is_max) || times.modified.map_or(false, is_max) { + if times.accessed.map_or(false, is_max) + || times.modified.map_or(false, is_max) + || times.created.map_or(false, is_max) + { return Err(io::const_io_error!( io::ErrorKind::InvalidInput, "Cannot set file timestamp to 0xFFFF_FFFF_FFFF_FFFF", )); } cvt(unsafe { + let created = + times.created.as_ref().map(|a| a as *const c::FILETIME).unwrap_or(ptr::null()); let accessed = times.accessed.as_ref().map(|a| a as *const c::FILETIME).unwrap_or(ptr::null()); let modified = times.modified.as_ref().map(|a| a as *const c::FILETIME).unwrap_or(ptr::null()); - c::SetFileTime(self.as_raw_handle(), ptr::null_mut(), accessed, modified) + c::SetFileTime(self.as_raw_handle(), created, accessed, modified) })?; Ok(()) } @@ -1005,6 +1015,10 @@ impl FileTimes { pub fn set_modified(&mut self, t: SystemTime) { self.modified = Some(t.into_inner()); } + + pub fn set_created(&mut self, t: SystemTime) { + self.created = Some(t.into_inner()); + } } impl FileType { diff --git a/library/std/src/sys_common/backtrace.rs b/library/std/src/sys_common/backtrace.rs index 8752f46ff81..6f020940df1 100644 --- a/library/std/src/sys_common/backtrace.rs +++ b/library/std/src/sys_common/backtrace.rs @@ -68,13 +68,17 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: } let mut hit = false; - let mut stop = false; backtrace_rs::resolve_frame_unsynchronized(frame, |symbol| { hit = true; + + // Any frames between `__rust_begin_short_backtrace` and `__rust_end_short_backtrace` + // are omitted from the backtrace in short mode, `__rust_end_short_backtrace` will be + // called before the panic hook, so we won't ignore any frames if there is no + // invoke of `__rust_begin_short_backtrace`. if print_fmt == PrintFmt::Short { if let Some(sym) = symbol.name().and_then(|s| s.as_str()) { if start && sym.contains("__rust_begin_short_backtrace") { - stop = true; + start = false; return; } if sym.contains("__rust_end_short_backtrace") { @@ -88,9 +92,6 @@ unsafe fn _print_fmt(fmt: &mut fmt::Formatter<'_>, print_fmt: PrintFmt) -> fmt:: res = bt_fmt.frame().symbol(frame, symbol); } }); - if stop { - return false; - } #[cfg(target_os = "nto")] if libc::__my_thread_exit as *mut libc::c_void == frame.ip() { if !hit && start { diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 3b7c31826b9..1b86d898cc7 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -18,8 +18,8 @@ use crate::fmt; /// target platform. It is instantiated with the [`thread_local!`] macro and the /// primary method is the [`with`] method. /// -/// The [`with`] method yields a reference to the contained value which cannot be -/// sent across threads or escape the given closure. +/// The [`with`] method yields a reference to the contained value which cannot +/// outlive the current thread or escape the given closure. /// /// [`thread_local!`]: crate::thread_local /// diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs index 6c9ce6fa0dd..b65e2572cc5 100644 --- a/library/std/src/thread/tests.rs +++ b/library/std/src/thread/tests.rs @@ -375,7 +375,9 @@ fn test_scoped_threads_nll() { // this is mostly a *compilation test* for this exact function: fn foo(x: &u8) { thread::scope(|s| { - s.spawn(|| drop(x)); + s.spawn(|| match x { + _ => (), + }); }); } // let's also run it for good measure diff --git a/src/bootstrap/Cargo.lock b/src/bootstrap/Cargo.lock index dfe6bb7f057..8f8778efee7 100644 --- a/src/bootstrap/Cargo.lock +++ b/src/bootstrap/Cargo.lock @@ -45,6 +45,7 @@ dependencies = [ "build_helper", "cc", "clap", + "clap_complete", "cmake", "fd-lock", "filetime", @@ -57,6 +58,7 @@ dependencies = [ "once_cell", "opener", "pretty_assertions", + "semver", "serde", "serde_derive", "serde_json", @@ -120,6 +122,15 @@ dependencies = [ ] [[package]] +name = "clap_complete" +version = "4.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36774babb166352bb4f7b9cb16f781ffa3439d2a8f12cd31bea85a38c888fea3" +dependencies = [ + "clap", +] + +[[package]] name = "clap_derive" version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -128,7 +139,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.15", + "syn 2.0.8", ] [[package]] @@ -477,9 +488,9 @@ dependencies = [ [[package]] name = "object" -version = "0.29.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53" +checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1" dependencies = [ "memchr", ] @@ -636,20 +647,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] name = "serde" -version = "1.0.137" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" [[package]] name = "serde_derive" -version = "1.0.137" +version = "1.0.160" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" dependencies = [ "proc-macro2", "quote", - "syn 1.0.102", + "syn 2.0.8", ] [[package]] @@ -687,9 +704,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.15" +version = "2.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" +checksum = "bcc02725fd69ab9f26eab07fad303e2497fad6fb9eba4f96c4d1687bdf704ad9" dependencies = [ "proc-macro2", "quote", diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index fd5eb740630..367c6190967 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -37,7 +37,7 @@ filetime = "0.2" cc = "1.0.69" libc = "0.2" hex = "0.4" -object = { version = "0.29.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] } +object = { version = "0.31.1", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] } serde = "1.0.137" # Directly use serde_derive rather than through the derive feature of serde to allow building both # in parallel and to allow serde_json and toml to start building as soon as serde has been built. @@ -56,6 +56,8 @@ walkdir = "2" # Dependencies needed by the build-metrics feature sysinfo = { version = "0.26.0", optional = true } clap = { version = "4.2.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] } +clap_complete = "4.2.2" +semver = "1.0.17" # Solaris doesn't support flock() and thus fd-lock is not option now [target.'cfg(not(target_os = "solaris"))'.dependencies] diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index f22cdad7df4..50ace987193 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -109,7 +109,7 @@ def _download(path, url, probably_big, verbose, exception): "-L", # Follow redirect. "-y", "30", "-Y", "10", # timeout if speed is < 10 bytes/sec for > 30 seconds "--connect-timeout", "30", # timeout if cannot connect within 30 seconds - "--retry", "3", "-Sf", url], + "--retry", "3", "-SRf", url], stdout=outfile, #Implements cli redirect operator '>' verbose=verbose, exception=True, # Will raise RuntimeError on failure diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 237f65b039f..cf7c6596c02 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -839,6 +839,7 @@ impl<'a> Builder<'a> { run::CollectLicenseMetadata, run::GenerateCopyright, run::GenerateWindowsSys, + run::GenerateCompletions, ), Kind::Setup => describe!(setup::Profile, setup::Hook, setup::Link, setup::Vscode), Kind::Clean => describe!(clean::CleanAll, clean::Rustc, clean::Std), @@ -941,7 +942,6 @@ impl<'a> Builder<'a> { self.run_step_descriptions(&Builder::get_step_descriptions(Kind::Doc), paths); } - /// NOTE: keep this in sync with `rustdoc::clean::utils::doc_rust_lang_org_channel`, or tests will fail on beta/stable. pub fn doc_rust_lang_org_channel(&self) -> String { let channel = match &*self.config.channel { "stable" => &self.version, diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index c32fe59bbf0..edca8fe9b13 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -146,6 +146,22 @@ fn alias_and_path_for_library() { ); } +#[test] +fn test_beta_rev_parsing() { + use crate::extract_beta_rev; + + // single digit revision + assert_eq!(extract_beta_rev("1.99.9-beta.7 (xxxxxx)"), Some("7".to_string())); + // multiple digits + assert_eq!(extract_beta_rev("1.99.9-beta.777 (xxxxxx)"), Some("777".to_string())); + // nightly channel (no beta revision) + assert_eq!(extract_beta_rev("1.99.9-nightly (xxxxxx)"), None); + // stable channel (no beta revision) + assert_eq!(extract_beta_rev("1.99.9 (xxxxxxx)"), None); + // invalid string + assert_eq!(extract_beta_rev("invalid"), None); +} + mod defaults { use super::{configure, first, run_build}; use crate::builder::*; diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index bf3bc3247ac..710c8b52194 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -24,6 +24,7 @@ pub use crate::flags::Subcommand; use crate::flags::{Color, Flags, Warnings}; use crate::util::{exe, output, t}; use once_cell::sync::OnceCell; +use semver::Version; use serde::{Deserialize, Deserializer}; use serde_derive::Deserialize; @@ -1019,6 +1020,7 @@ impl Config { config.download_beta_toolchain(); config.out.join(config.build.triple).join("stage0/bin/rustc") }); + config.initial_cargo = build .cargo .map(|cargo| { @@ -1680,6 +1682,42 @@ impl Config { self.rust_codegen_backends.get(0).cloned() } + pub fn check_build_rustc_version(&self) { + if self.dry_run() { + return; + } + + // check rustc version is same or lower with 1 apart from the building one + let mut cmd = Command::new(&self.initial_rustc); + cmd.arg("--version"); + let rustc_output = output(&mut cmd) + .lines() + .next() + .unwrap() + .split(' ') + .nth(1) + .unwrap() + .split('-') + .next() + .unwrap() + .to_owned(); + let rustc_version = Version::parse(&rustc_output.trim()).unwrap(); + let source_version = + Version::parse(&fs::read_to_string(self.src.join("src/version")).unwrap().trim()) + .unwrap(); + if !(source_version == rustc_version + || (source_version.major == rustc_version.major + && source_version.minor == rustc_version.minor + 1)) + { + let prev_version = format!("{}.{}.x", source_version.major, source_version.minor - 1); + eprintln!( + "Unexpected rustc version: {}, we should use {}/{} to build source with {}", + rustc_version, prev_version, source_version, source_version + ); + crate::detail_exit(1); + } + } + /// Returns the commit to download, or `None` if we shouldn't download CI artifacts. fn download_ci_rustc_commit(&self, download_rustc: Option<StringOrBool>) -> Option<String> { // If `download-rustc` is not set, default to rebuilding. diff --git a/src/bootstrap/download.rs b/src/bootstrap/download.rs index 3e82a381a1b..25df5b2573b 100644 --- a/src/bootstrap/download.rs +++ b/src/bootstrap/download.rs @@ -219,7 +219,7 @@ impl Config { "30", // timeout if cannot connect within 30 seconds "--retry", "3", - "-Sf", + "-SRf", ]); curl.arg(url); let f = File::create(tempfile).unwrap(); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index c79a1bf9563..d8b298b59a3 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -3,9 +3,9 @@ //! This module implements the command-line parsing of the build system which //! has various flags to configure how it's run. -use std::path::PathBuf; +use std::path::{Path, PathBuf}; -use clap::{Parser, ValueEnum}; +use clap::{CommandFactory, Parser, ValueEnum}; use crate::builder::{Builder, Kind}; use crate::config::{target_selection_list, Config, TargetSelectionList}; @@ -54,15 +54,15 @@ pub struct Flags { /// Build directory, overrides `build.build-dir` in `config.toml` pub build_dir: Option<PathBuf>, - #[arg(global(true), long, value_name = "BUILD")] + #[arg(global(true), long, value_hint = clap::ValueHint::Other, value_name = "BUILD")] /// build target of the stage0 compiler pub build: Option<String>, - #[arg(global(true), long, value_name = "HOST", value_parser = target_selection_list)] + #[arg(global(true), long, value_hint = clap::ValueHint::Other, value_name = "HOST", value_parser = target_selection_list)] /// host targets to build pub host: Option<TargetSelectionList>, - #[arg(global(true), long, value_name = "TARGET", value_parser = target_selection_list)] + #[arg(global(true), long, value_hint = clap::ValueHint::Other, value_name = "TARGET", value_parser = target_selection_list)] /// target targets to build pub target: Option<TargetSelectionList>, @@ -73,7 +73,7 @@ pub struct Flags { /// include default paths in addition to the provided ones pub include_default_paths: bool, - #[arg(global(true), long)] + #[arg(global(true), value_hint = clap::ValueHint::Other, long)] pub rustc_error_format: Option<String>, #[arg(global(true), long, value_hint = clap::ValueHint::CommandString, value_name = "CMD")] @@ -82,16 +82,16 @@ pub struct Flags { #[arg(global(true), long)] /// dry run; don't build anything pub dry_run: bool, - #[arg(global(true), long, value_name = "N")] + #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "N")] /// stage to build (indicates compiler to use/test, e.g., stage 0 uses the /// bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.) pub stage: Option<u32>, - #[arg(global(true), long, value_name = "N")] + #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "N")] /// stage(s) to keep without recompiling /// (pass multiple times to keep e.g., both stages 0 and 1) pub keep_stage: Vec<u32>, - #[arg(global(true), long, value_name = "N")] + #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "N")] /// stage(s) of the standard library to keep without recompiling /// (pass multiple times to keep e.g., both stages 0 and 1) pub keep_stage_std: Vec<u32>, @@ -103,6 +103,7 @@ pub struct Flags { global(true), short, long, + value_hint = clap::ValueHint::Other, default_value_t = std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get), value_name = "JOBS" )] @@ -117,7 +118,7 @@ pub struct Flags { /// otherwise, use the default configured behaviour pub warnings: Warnings, - #[arg(global(true), long, value_name = "FORMAT")] + #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "FORMAT")] /// rustc error format pub error_format: Option<String>, #[arg(global(true), long)] @@ -133,13 +134,13 @@ pub struct Flags { #[arg(global(true), long, value_name = "VALUE")] pub llvm_skip_rebuild: Option<bool>, /// generate PGO profile with rustc build - #[arg(global(true), long, value_name = "PROFILE")] + #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] pub rust_profile_generate: Option<String>, /// use PGO profile for rustc build - #[arg(global(true), long, value_name = "PROFILE")] + #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] pub rust_profile_use: Option<String>, /// use PGO profile for LLVM build - #[arg(global(true), long, value_name = "PROFILE")] + #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] pub llvm_profile_use: Option<String>, // LLVM doesn't support a custom location for generating profile // information. @@ -152,7 +153,7 @@ pub struct Flags { #[arg(global(true), long)] pub llvm_bolt_profile_generate: bool, /// use BOLT profile for LLVM build - #[arg(global(true), long, value_name = "PROFILE")] + #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] pub llvm_bolt_profile_use: Option<String>, #[arg(global(true))] /// paths for the subcommand @@ -364,7 +365,7 @@ pub enum Subcommand { #[arg(long)] all: bool, }, - /// Duild distribution artifacts + /// Build distribution artifacts Dist, /// Install distribution artifacts Install, @@ -524,3 +525,23 @@ impl Subcommand { } } } + +/// Returns the shell completion for a given shell, if the result differs from the current +/// content of `path`. If `path` does not exist, always returns `Some`. +pub fn get_completion<G: clap_complete::Generator>(shell: G, path: &Path) -> Option<String> { + let mut cmd = Flags::command(); + let current = if !path.exists() { + String::new() + } else { + std::fs::read_to_string(path).unwrap_or_else(|_| { + eprintln!("couldn't read {}", path.display()); + crate::detail_exit(1) + }) + }; + let mut buf = Vec::new(); + clap_complete::generate(shell, &mut cmd, "x.py", &mut buf); + if buf == current.as_bytes() { + return None; + } + Some(String::from_utf8(buf).expect("completion script should be UTF-8")) +} diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 994336977dc..6ee50ee6573 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -414,6 +414,7 @@ impl Build { bootstrap_out.display() ) } + config.check_build_rustc_version(); if rust_info.is_from_tarball() && config.description.is_none() { config.description = Some("built from a source tarball".to_owned()); @@ -1323,7 +1324,7 @@ impl Build { match &self.config.channel[..] { "stable" => num.to_string(), "beta" => { - if self.rust_info().is_managed_git_subrepository() && !self.config.omit_git_hash { + if !self.config.omit_git_hash { format!("{}-beta.{}", num, self.beta_prerelease_version()) } else { format!("{}-beta", num) @@ -1335,18 +1336,28 @@ impl Build { } fn beta_prerelease_version(&self) -> u32 { + fn extract_beta_rev_from_file<P: AsRef<Path>>(version_file: P) -> Option<String> { + let version = fs::read_to_string(version_file).ok()?; + + extract_beta_rev(&version) + } + if let Some(s) = self.prerelease_version.get() { return s; } - // Figure out how many merge commits happened since we branched off master. - // That's our beta number! - // (Note that we use a `..` range, not the `...` symmetric difference.) - let count = + // First check if there is a version file available. + // If available, we read the beta revision from that file. + // This only happens when building from a source tarball when Git should not be used. + let count = extract_beta_rev_from_file(self.src.join("version")).unwrap_or_else(|| { + // Figure out how many merge commits happened since we branched off master. + // That's our beta number! + // (Note that we use a `..` range, not the `...` symmetric difference.) output(self.config.git().arg("rev-list").arg("--count").arg("--merges").arg(format!( "refs/remotes/origin/{}..HEAD", self.config.stage0_metadata.config.nightly_branch - ))); + ))) + }); let n = count.trim().parse().unwrap(); self.prerelease_version.set(Some(n)); n @@ -1706,6 +1717,17 @@ to download LLVM rather than building it. } } +/// Extract the beta revision from the full version string. +/// +/// The full version string looks like "a.b.c-beta.y". And we need to extract +/// the "y" part from the string. +pub fn extract_beta_rev(version: &str) -> Option<String> { + let parts = version.splitn(2, "-beta.").collect::<Vec<_>>(); + let count = parts.get(1).and_then(|s| s.find(' ').map(|p| (&s[..p]).to_string())); + + count +} + #[cfg(unix)] fn chmod(path: &Path, perms: u32) { use std::os::unix::fs::*; diff --git a/src/bootstrap/render_tests.rs b/src/bootstrap/render_tests.rs index bedf34d89e8..fa0a4806618 100644 --- a/src/bootstrap/render_tests.rs +++ b/src/bootstrap/render_tests.rs @@ -168,9 +168,14 @@ impl<'a> Renderer<'a> { if !self.failures.is_empty() { println!("\nfailures:\n"); for failure in &self.failures { - if let Some(stdout) = &failure.stdout { + if failure.stdout.is_some() || failure.message.is_some() { println!("---- {} stdout ----", failure.name); - println!("{stdout}"); + if let Some(stdout) = &failure.stdout { + println!("{stdout}"); + } + if let Some(message) = &failure.message { + println!("note: {message}"); + } } } diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index 57f3119e322..ec01f744b82 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -1,9 +1,12 @@ use std::path::PathBuf; use std::process::Command; +use clap_complete::shells; + use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::config::TargetSelection; use crate::dist::distdir; +use crate::flags::get_completion; use crate::test; use crate::tool::{self, SourceType, Tool}; use crate::util::output; @@ -275,3 +278,34 @@ impl Step for GenerateWindowsSys { builder.run(&mut cmd); } } + +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +pub struct GenerateCompletions; + +impl Step for GenerateCompletions { + type Output = (); + + /// Uses `clap_complete` to generate shell completions. + fn run(self, builder: &Builder<'_>) { + // FIXME(clubby789): enable zsh when clap#4898 is fixed + let [bash, fish, powershell] = ["x.py.sh", "x.py.fish", "x.py.ps1"] + .map(|filename| builder.src.join("src/etc/completions").join(filename)); + if let Some(comp) = get_completion(shells::Bash, &bash) { + std::fs::write(&bash, comp).expect("writing bash completion"); + } + if let Some(comp) = get_completion(shells::Fish, &fish) { + std::fs::write(&fish, comp).expect("writing fish completion"); + } + if let Some(comp) = get_completion(shells::PowerShell, &powershell) { + std::fs::write(&powershell, comp).expect("writing powershell completion"); + } + } + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.alias("generate-completions") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(GenerateCompletions); + } +} diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index 854b7f5bd3a..2b72d6c48eb 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -10,6 +10,8 @@ use std::iter; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; +use clap_complete::shells; + use crate::builder::crate_description; use crate::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step}; use crate::cache::Interned; @@ -613,6 +615,23 @@ impl Step for Miri { builder.run(&mut cargo); } + // Run it again for mir-opt-level 4 to catch some miscompilations. + if builder.config.test_args().is_empty() { + cargo.env("MIRIFLAGS", "-O -Zmir-opt-level=4 -Cdebug-assertions=yes"); + // Optimizations can change backtraces + cargo.env("MIRI_SKIP_UI_CHECKS", "1"); + // `MIRI_SKIP_UI_CHECKS` and `MIRI_BLESS` are incompatible + cargo.env_remove("MIRI_BLESS"); + // Optimizations can change error locations and remove UB so don't run `fail` tests. + cargo.args(&["tests/pass", "tests/panic"]); + + let mut cargo = prepare_cargo_test(cargo, &[], &[], "miri", compiler, target, builder); + { + let _time = util::timeit(&builder); + builder.run(&mut cargo); + } + } + // # Run `cargo miri test`. // This is just a smoke test (Miri's own CI invokes this in a bunch of different ways and ensures // that we get the desired output), but that is sufficient to make sure that the libtest harness @@ -644,8 +663,10 @@ impl Step for Miri { cargo.env("RUST_BACKTRACE", "1"); let mut cargo = Command::from(cargo); - let _time = util::timeit(&builder); - builder.run(&mut cargo); + { + let _time = util::timeit(&builder); + builder.run(&mut cargo); + } } } @@ -1121,7 +1142,24 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy` builder.info("tidy check"); try_run(builder, &mut cmd); - builder.ensure(ExpandYamlAnchors {}); + builder.ensure(ExpandYamlAnchors); + + builder.info("x.py completions check"); + let [bash, fish, powershell] = ["x.py.sh", "x.py.fish", "x.py.ps1"] + .map(|filename| builder.src.join("src/etc/completions").join(filename)); + if builder.config.cmd.bless() { + builder.ensure(crate::run::GenerateCompletions); + } else { + if crate::flags::get_completion(shells::Bash, &bash).is_some() + || crate::flags::get_completion(shells::Fish, &fish).is_some() + || crate::flags::get_completion(shells::PowerShell, &powershell).is_some() + { + eprintln!( + "x.py completions were changed; run `x.py run generate-completions` to update them" + ); + crate::detail_exit(1); + } + } } fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version index d183d4ace05..806935b827f 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version @@ -1 +1 @@ -0.16.0 \ No newline at end of file +0.16.4 \ No newline at end of file diff --git a/src/ci/stage-build.py b/src/ci/stage-build.py index 7cd5e88f6a2..8d03d3759bf 100644 --- a/src/ci/stage-build.py +++ b/src/ci/stage-build.py @@ -48,7 +48,6 @@ RUSTC_PGO_CRATES = [ LLVM_BOLT_CRATES = LLVM_PGO_CRATES - class Pipeline: # Paths def checkout_path(self) -> Path: @@ -451,6 +450,44 @@ def cmd( ) return subprocess.run(args, env=environment, check=True) +class BenchmarkRunner: + def run_rustc(self, pipeline: Pipeline): + raise NotImplementedError + + def run_llvm(self, pipeline: Pipeline): + raise NotImplementedError + + def run_bolt(self, pipeline: Pipeline): + raise NotImplementedError + +class DefaultBenchmarkRunner(BenchmarkRunner): + def run_rustc(self, pipeline: Pipeline): + # Here we're profiling the `rustc` frontend, so we also include `Check`. + # The benchmark set includes various stress tests that put the frontend under pressure. + run_compiler_benchmarks( + pipeline, + profiles=["Check", "Debug", "Opt"], + scenarios=["All"], + crates=RUSTC_PGO_CRATES, + env=dict( + LLVM_PROFILE_FILE=str(pipeline.rustc_profile_template_path()) + ) + ) + def run_llvm(self, pipeline: Pipeline): + run_compiler_benchmarks( + pipeline, + profiles=["Debug", "Opt"], + scenarios=["Full"], + crates=LLVM_PGO_CRATES + ) + + def run_bolt(self, pipeline: Pipeline): + run_compiler_benchmarks( + pipeline, + profiles=["Check", "Debug", "Opt"], + scenarios=["Full"], + crates=LLVM_BOLT_CRATES + ) def run_compiler_benchmarks( pipeline: Pipeline, @@ -580,14 +617,10 @@ def create_pipeline() -> Pipeline: raise Exception(f"Optimized build is not supported for platform {sys.platform}") -def gather_llvm_profiles(pipeline: Pipeline): +def gather_llvm_profiles(pipeline: Pipeline, runner: BenchmarkRunner): LOGGER.info("Running benchmarks with PGO instrumented LLVM") - run_compiler_benchmarks( - pipeline, - profiles=["Debug", "Opt"], - scenarios=["Full"], - crates=LLVM_PGO_CRATES - ) + + runner.run_llvm(pipeline) profile_path = pipeline.llvm_profile_merged_file() LOGGER.info(f"Merging LLVM PGO profiles to {profile_path}") @@ -609,20 +642,12 @@ def gather_llvm_profiles(pipeline: Pipeline): delete_directory(pipeline.llvm_profile_dir_root()) -def gather_rustc_profiles(pipeline: Pipeline): +def gather_rustc_profiles(pipeline: Pipeline, runner: BenchmarkRunner): LOGGER.info("Running benchmarks with PGO instrumented rustc") - # Here we're profiling the `rustc` frontend, so we also include `Check`. - # The benchmark set includes various stress tests that put the frontend under pressure. - run_compiler_benchmarks( - pipeline, - profiles=["Check", "Debug", "Opt"], - scenarios=["All"], - crates=RUSTC_PGO_CRATES, - env=dict( - LLVM_PROFILE_FILE=str(pipeline.rustc_profile_template_path()) - ) - ) + + runner.run_rustc(pipeline) + profile_path = pipeline.rustc_profile_merged_file() LOGGER.info(f"Merging Rustc PGO profiles to {profile_path}") @@ -644,14 +669,10 @@ def gather_rustc_profiles(pipeline: Pipeline): delete_directory(pipeline.rustc_profile_dir_root()) -def gather_llvm_bolt_profiles(pipeline: Pipeline): +def gather_llvm_bolt_profiles(pipeline: Pipeline, runner: BenchmarkRunner): LOGGER.info("Running benchmarks with BOLT instrumented LLVM") - run_compiler_benchmarks( - pipeline, - profiles=["Check", "Debug", "Opt"], - scenarios=["Full"], - crates=LLVM_BOLT_CRATES - ) + + runner.run_bolt(pipeline) merged_profile_path = pipeline.llvm_bolt_profile_merged_file() profile_files_path = Path("/tmp/prof.fdata") @@ -744,7 +765,7 @@ def record_metrics(pipeline: Pipeline, timer: Timer): log_metrics(metrics) -def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: List[str]): +def execute_build_pipeline(timer: Timer, pipeline: Pipeline, runner: BenchmarkRunner, final_build_args: List[str]): # Clear and prepare tmp directory shutil.rmtree(pipeline.opt_artifacts(), ignore_errors=True) os.makedirs(pipeline.opt_artifacts(), exist_ok=True) @@ -762,7 +783,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L record_metrics(pipeline, rustc_build) with stage1.section("Gather profiles"): - gather_llvm_profiles(pipeline) + gather_llvm_profiles(pipeline, runner) print_free_disk_space(pipeline) clear_llvm_files(pipeline) @@ -781,7 +802,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L record_metrics(pipeline, rustc_build) with stage2.section("Gather profiles"): - gather_rustc_profiles(pipeline) + gather_rustc_profiles(pipeline, runner) print_free_disk_space(pipeline) clear_llvm_files(pipeline) @@ -804,7 +825,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L record_metrics(pipeline, rustc_build) with stage3.section("Gather profiles"): - gather_llvm_bolt_profiles(pipeline) + gather_llvm_bolt_profiles(pipeline, runner) # LLVM is not being cleared here, we want to reuse the previous build print_free_disk_space(pipeline) @@ -819,7 +840,7 @@ def execute_build_pipeline(timer: Timer, pipeline: Pipeline, final_build_args: L record_metrics(pipeline, stage4) -if __name__ == "__main__": +def run(runner: BenchmarkRunner): logging.basicConfig( level=logging.DEBUG, format="%(name)s %(levelname)-4s: %(message)s", @@ -832,8 +853,9 @@ if __name__ == "__main__": timer = Timer() pipeline = create_pipeline() + try: - execute_build_pipeline(timer, pipeline, build_args) + execute_build_pipeline(timer, pipeline, runner, build_args) except BaseException as e: LOGGER.error("The multi-stage build has failed") raise e @@ -842,3 +864,7 @@ if __name__ == "__main__": print_free_disk_space(pipeline) print_binary_sizes(pipeline) + +if __name__ == "__main__": + runner = DefaultBenchmarkRunner() + run(runner) diff --git a/src/etc/completions/x.py.fish b/src/etc/completions/x.py.fish new file mode 100644 index 00000000000..4eddd5cedf1 --- /dev/null +++ b/src/etc/completions/x.py.fish @@ -0,0 +1,475 @@ +complete -c x.py -n "__fish_use_subcommand" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_use_subcommand" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_use_subcommand" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_use_subcommand" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_use_subcommand" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_use_subcommand" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_use_subcommand" -l rustc-error-format -r -f +complete -c x.py -n "__fish_use_subcommand" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_use_subcommand" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_use_subcommand" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_use_subcommand" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_use_subcommand" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_use_subcommand" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_use_subcommand" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_use_subcommand" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_use_subcommand" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_use_subcommand" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_use_subcommand" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_use_subcommand" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_use_subcommand" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_use_subcommand" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_use_subcommand" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_use_subcommand" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_use_subcommand" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_use_subcommand" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_use_subcommand" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_use_subcommand" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_use_subcommand" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_use_subcommand" -s h -l help -d 'Print help' +complete -c x.py -n "__fish_use_subcommand" -f -a "build" -d 'Compile either the compiler or libraries' +complete -c x.py -n "__fish_use_subcommand" -f -a "check" -d 'Compile either the compiler or libraries, using cargo check' +complete -c x.py -n "__fish_use_subcommand" -f -a "clippy" -d 'Run Clippy (uses rustup/cargo-installed clippy binary)' +complete -c x.py -n "__fish_use_subcommand" -f -a "fix" -d 'Run cargo fix' +complete -c x.py -n "__fish_use_subcommand" -f -a "fmt" -d 'Run rustfmt' +complete -c x.py -n "__fish_use_subcommand" -f -a "doc" -d 'Build documentation' +complete -c x.py -n "__fish_use_subcommand" -f -a "test" -d 'Build and run some test suites' +complete -c x.py -n "__fish_use_subcommand" -f -a "bench" -d 'Build and run some benchmarks' +complete -c x.py -n "__fish_use_subcommand" -f -a "clean" -d 'Clean out build directories' +complete -c x.py -n "__fish_use_subcommand" -f -a "dist" -d 'Build distribution artifacts' +complete -c x.py -n "__fish_use_subcommand" -f -a "install" -d 'Install distribution artifacts' +complete -c x.py -n "__fish_use_subcommand" -f -a "run" -d 'Run tools contained in this repository' +complete -c x.py -n "__fish_use_subcommand" -f -a "setup" -d 'Set up the environment for development' +complete -c x.py -n "__fish_use_subcommand" -f -a "suggest" -d 'Suggest a subset of tests to run, based on modified files' +complete -c x.py -n "__fish_seen_subcommand_from build" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from build" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from build" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from build" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from build" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from build" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from build" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from build" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from build" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from build" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from build" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from build" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from build" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from build" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from build" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from build" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from build" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from build" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from build" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from build" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from build" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from build" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from build" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from build" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from build" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from check" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from check" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from check" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from check" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from check" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from check" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from check" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from check" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from check" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from check" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from check" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from check" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from check" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from check" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from check" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from check" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from check" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from check" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from check" -l all-targets -d 'Check all targets' +complete -c x.py -n "__fish_seen_subcommand_from check" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from check" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from check" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from check" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from check" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from check" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from check" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from clippy" -s A -d 'clippy lints to allow' -r +complete -c x.py -n "__fish_seen_subcommand_from clippy" -s D -d 'clippy lints to deny' -r +complete -c x.py -n "__fish_seen_subcommand_from clippy" -s W -d 'clippy lints to warn on' -r +complete -c x.py -n "__fish_seen_subcommand_from clippy" -s F -d 'clippy lints to forbid' -r +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from clippy" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l fix +complete -c x.py -n "__fish_seen_subcommand_from clippy" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from clippy" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from clippy" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from clippy" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from fix" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fix" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from fix" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fix" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fix" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fix" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fix" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from fix" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from fix" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fix" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fix" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fix" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from fix" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fix" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from fix" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fix" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from fix" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fix" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fix" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from fix" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from fix" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from fix" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from fix" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from fix" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from fix" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from fmt" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l check -d 'check formatting instead of applying' +complete -c x.py -n "__fish_seen_subcommand_from fmt" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from fmt" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from fmt" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from fmt" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from doc" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from doc" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from doc" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from doc" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from doc" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from doc" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from doc" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from doc" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from doc" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from doc" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from doc" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from doc" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from doc" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from doc" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from doc" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from doc" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from doc" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from doc" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from doc" -l open -d 'open the docs in a browser' +complete -c x.py -n "__fish_seen_subcommand_from doc" -l json -d 'render the documentation in JSON format in addition to the usual HTML format' +complete -c x.py -n "__fish_seen_subcommand_from doc" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from doc" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from doc" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from doc" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from doc" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from doc" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from doc" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from test" -l skip -d 'skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times' -r +complete -c x.py -n "__fish_seen_subcommand_from test" -l test-args -d 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)' -r +complete -c x.py -n "__fish_seen_subcommand_from test" -l rustc-args -d 'extra options to pass the compiler when running tests' -r +complete -c x.py -n "__fish_seen_subcommand_from test" -l compare-mode -d 'mode describing what file the actual ui output will be compared to' -r +complete -c x.py -n "__fish_seen_subcommand_from test" -l pass -d 'force {check,build,run}-pass tests to this mode' -r +complete -c x.py -n "__fish_seen_subcommand_from test" -l run -d 'whether to execute run-* tests' -r +complete -c x.py -n "__fish_seen_subcommand_from test" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from test" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from test" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from test" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from test" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from test" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from test" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from test" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from test" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from test" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from test" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from test" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from test" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from test" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from test" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from test" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from test" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from test" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from test" -l no-fail-fast -d 'run all tests regardless of failure' +complete -c x.py -n "__fish_seen_subcommand_from test" -l no-doc -d 'do not run doc tests' +complete -c x.py -n "__fish_seen_subcommand_from test" -l doc -d 'only run doc tests' +complete -c x.py -n "__fish_seen_subcommand_from test" -l bless -d 'whether to automatically update stderr/stdout files' +complete -c x.py -n "__fish_seen_subcommand_from test" -l force-rerun -d 'rerun tests even if the inputs are unchanged' +complete -c x.py -n "__fish_seen_subcommand_from test" -l only-modified -d 'only run tests that result has been changed' +complete -c x.py -n "__fish_seen_subcommand_from test" -l rustfix-coverage -d 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`' +complete -c x.py -n "__fish_seen_subcommand_from test" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from test" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from test" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from test" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from test" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from test" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from test" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from bench" -l test-args -r +complete -c x.py -n "__fish_seen_subcommand_from bench" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from bench" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from bench" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from bench" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from bench" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from bench" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from bench" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from bench" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from bench" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from bench" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from bench" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from bench" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from bench" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from bench" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from bench" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from bench" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from bench" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from bench" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from bench" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from bench" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from bench" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from bench" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from bench" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from bench" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from bench" -s h -l help -d 'Print help' +complete -c x.py -n "__fish_seen_subcommand_from clean" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clean" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from clean" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clean" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clean" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clean" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clean" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from clean" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from clean" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clean" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clean" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clean" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from clean" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clean" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from clean" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from clean" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from clean" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clean" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from clean" -l all +complete -c x.py -n "__fish_seen_subcommand_from clean" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from clean" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from clean" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from clean" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from clean" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from clean" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from clean" -s h -l help -d 'Print help' +complete -c x.py -n "__fish_seen_subcommand_from dist" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from dist" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from dist" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from dist" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from dist" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from dist" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from dist" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from dist" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from dist" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from dist" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from dist" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from dist" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from dist" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from dist" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from dist" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from dist" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from dist" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from dist" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from dist" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from dist" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from dist" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from dist" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from dist" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from dist" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from dist" -s h -l help -d 'Print help' +complete -c x.py -n "__fish_seen_subcommand_from install" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from install" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from install" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from install" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from install" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from install" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from install" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from install" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from install" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from install" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from install" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from install" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from install" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from install" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from install" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from install" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from install" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from install" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from install" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from install" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from install" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from install" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from install" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from install" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from install" -s h -l help -d 'Print help' +complete -c x.py -n "__fish_seen_subcommand_from run" -l args -d 'arguments for the tool' -r +complete -c x.py -n "__fish_seen_subcommand_from run" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from run" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from run" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from run" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from run" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from run" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from run" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from run" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from run" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from run" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from run" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from run" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from run" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from run" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from run" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from run" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from run" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from run" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from run" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from run" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from run" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from run" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from run" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from run" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from run" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from setup" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from setup" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from setup" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from setup" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from setup" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from setup" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from setup" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from setup" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from setup" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from setup" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from setup" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from setup" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from setup" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from setup" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from setup" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from setup" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from setup" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from setup" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from setup" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from setup" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from setup" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from setup" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from setup" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from setup" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from setup" -s h -l help -d 'Print help (see more with \'--help\')' +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l config -d 'TOML configuration file for build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l build-dir -d 'Build directory, overrides `build.build-dir` in `config.toml`' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l build -d 'build target of the stage0 compiler' -r -f +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l host -d 'host targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l target -d 'target targets to build' -r -f +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l exclude -d 'build paths to exclude' -r -F +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l rustc-error-format -r -f +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l on-fail -d 'command to run on failure' -r -f -a "(__fish_complete_command)" +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l stage -d 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l keep-stage -d 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l keep-stage-std -d 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)' -r -f +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l src -d 'path to the root of the rust checkout' -r -f -a "(__fish_complete_directories)" +complete -c x.py -n "__fish_seen_subcommand_from suggest" -s j -l jobs -d 'number of jobs to run in parallel' -r -f +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l warnings -d 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour' -r -f -a "{deny ,warn ,default }" +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l error-format -d 'rustc error format' -r -f +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l color -d 'whether to use color in cargo and rustc output' -r -f -a "{always ,never ,auto }" +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-skip-rebuild -d 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml' -r -f -a "{true ,false }" +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l rust-profile-generate -d 'generate PGO profile with rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l rust-profile-use -d 'use PGO profile for rustc build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-profile-use -d 'use PGO profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-bolt-profile-use -d 'use BOLT profile for LLVM build' -r -F +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l run -d 'run suggested tests' +complete -c x.py -n "__fish_seen_subcommand_from suggest" -s v -l verbose -d 'use verbose output (-vv for very verbose)' +complete -c x.py -n "__fish_seen_subcommand_from suggest" -s i -l incremental -d 'use incremental compilation' +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l include-default-paths -d 'include default paths in addition to the provided ones' +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l dry-run -d 'dry run; don\'t build anything' +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l json-output -d 'use message-format=json' +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-profile-generate -d 'generate PGO profile with llvm built for rustc' +complete -c x.py -n "__fish_seen_subcommand_from suggest" -l llvm-bolt-profile-generate -d 'generate BOLT profile for LLVM build' +complete -c x.py -n "__fish_seen_subcommand_from suggest" -s h -l help -d 'Print help (see more with \'--help\')' diff --git a/src/etc/completions/x.py.ps1 b/src/etc/completions/x.py.ps1 new file mode 100644 index 00000000000..59fabf53f98 --- /dev/null +++ b/src/etc/completions/x.py.ps1 @@ -0,0 +1,607 @@ + +using namespace System.Management.Automation +using namespace System.Management.Automation.Language + +Register-ArgumentCompleter -Native -CommandName 'x.py' -ScriptBlock { + param($wordToComplete, $commandAst, $cursorPosition) + + $commandElements = $commandAst.CommandElements + $command = @( + 'x.py' + for ($i = 1; $i -lt $commandElements.Count; $i++) { + $element = $commandElements[$i] + if ($element -isnot [StringConstantExpressionAst] -or + $element.StringConstantType -ne [StringConstantType]::BareWord -or + $element.Value.StartsWith('-') -or + $element.Value -eq $wordToComplete) { + break + } + $element.Value + }) -join ';' + + $completions = @(switch ($command) { + 'x.py' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('build', 'build', [CompletionResultType]::ParameterValue, 'Compile either the compiler or libraries') + [CompletionResult]::new('check', 'check', [CompletionResultType]::ParameterValue, 'Compile either the compiler or libraries, using cargo check') + [CompletionResult]::new('clippy', 'clippy', [CompletionResultType]::ParameterValue, 'Run Clippy (uses rustup/cargo-installed clippy binary)') + [CompletionResult]::new('fix', 'fix', [CompletionResultType]::ParameterValue, 'Run cargo fix') + [CompletionResult]::new('fmt', 'fmt', [CompletionResultType]::ParameterValue, 'Run rustfmt') + [CompletionResult]::new('doc', 'doc', [CompletionResultType]::ParameterValue, 'Build documentation') + [CompletionResult]::new('test', 'test', [CompletionResultType]::ParameterValue, 'Build and run some test suites') + [CompletionResult]::new('bench', 'bench', [CompletionResultType]::ParameterValue, 'Build and run some benchmarks') + [CompletionResult]::new('clean', 'clean', [CompletionResultType]::ParameterValue, 'Clean out build directories') + [CompletionResult]::new('dist', 'dist', [CompletionResultType]::ParameterValue, 'Build distribution artifacts') + [CompletionResult]::new('install', 'install', [CompletionResultType]::ParameterValue, 'Install distribution artifacts') + [CompletionResult]::new('run', 'run', [CompletionResultType]::ParameterValue, 'Run tools contained in this repository') + [CompletionResult]::new('setup', 'setup', [CompletionResultType]::ParameterValue, 'Set up the environment for development') + [CompletionResult]::new('suggest', 'suggest', [CompletionResultType]::ParameterValue, 'Suggest a subset of tests to run, based on modified files') + break + } + 'x.py;build' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } + 'x.py;check' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--all-targets', 'all-targets', [CompletionResultType]::ParameterName, 'Check all targets') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } + 'x.py;clippy' { + [CompletionResult]::new('-A', 'A', [CompletionResultType]::ParameterName, 'clippy lints to allow') + [CompletionResult]::new('-D', 'D', [CompletionResultType]::ParameterName, 'clippy lints to deny') + [CompletionResult]::new('-W', 'W', [CompletionResultType]::ParameterName, 'clippy lints to warn on') + [CompletionResult]::new('-F', 'F', [CompletionResultType]::ParameterName, 'clippy lints to forbid') + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--fix', 'fix', [CompletionResultType]::ParameterName, 'fix') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } + 'x.py;fix' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } + 'x.py;fmt' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--check', 'check', [CompletionResultType]::ParameterName, 'check formatting instead of applying') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } + 'x.py;doc' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--open', 'open', [CompletionResultType]::ParameterName, 'open the docs in a browser') + [CompletionResult]::new('--json', 'json', [CompletionResultType]::ParameterName, 'render the documentation in JSON format in addition to the usual HTML format') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } + 'x.py;test' { + [CompletionResult]::new('--skip', 'skip', [CompletionResultType]::ParameterName, 'skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times') + [CompletionResult]::new('--test-args', 'test-args', [CompletionResultType]::ParameterName, 'extra arguments to be passed for the test tool being used (e.g. libtest, compiletest or rustdoc)') + [CompletionResult]::new('--rustc-args', 'rustc-args', [CompletionResultType]::ParameterName, 'extra options to pass the compiler when running tests') + [CompletionResult]::new('--compare-mode', 'compare-mode', [CompletionResultType]::ParameterName, 'mode describing what file the actual ui output will be compared to') + [CompletionResult]::new('--pass', 'pass', [CompletionResultType]::ParameterName, 'force {check,build,run}-pass tests to this mode') + [CompletionResult]::new('--run', 'run', [CompletionResultType]::ParameterName, 'whether to execute run-* tests') + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--no-fail-fast', 'no-fail-fast', [CompletionResultType]::ParameterName, 'run all tests regardless of failure') + [CompletionResult]::new('--no-doc', 'no-doc', [CompletionResultType]::ParameterName, 'do not run doc tests') + [CompletionResult]::new('--doc', 'doc', [CompletionResultType]::ParameterName, 'only run doc tests') + [CompletionResult]::new('--bless', 'bless', [CompletionResultType]::ParameterName, 'whether to automatically update stderr/stdout files') + [CompletionResult]::new('--force-rerun', 'force-rerun', [CompletionResultType]::ParameterName, 'rerun tests even if the inputs are unchanged') + [CompletionResult]::new('--only-modified', 'only-modified', [CompletionResultType]::ParameterName, 'only run tests that result has been changed') + [CompletionResult]::new('--rustfix-coverage', 'rustfix-coverage', [CompletionResultType]::ParameterName, 'enable this to generate a Rustfix coverage file, which is saved in `/<build_base>/rustfix_missing_coverage.txt`') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } + 'x.py;bench' { + [CompletionResult]::new('--test-args', 'test-args', [CompletionResultType]::ParameterName, 'test-args') + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') + break + } + 'x.py;clean' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--all', 'all', [CompletionResultType]::ParameterName, 'all') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') + break + } + 'x.py;dist' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') + break + } + 'x.py;install' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help') + break + } + 'x.py;run' { + [CompletionResult]::new('--args', 'args', [CompletionResultType]::ParameterName, 'arguments for the tool') + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } + 'x.py;setup' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } + 'x.py;suggest' { + [CompletionResult]::new('--config', 'config', [CompletionResultType]::ParameterName, 'TOML configuration file for build') + [CompletionResult]::new('--build-dir', 'build-dir', [CompletionResultType]::ParameterName, 'Build directory, overrides `build.build-dir` in `config.toml`') + [CompletionResult]::new('--build', 'build', [CompletionResultType]::ParameterName, 'build target of the stage0 compiler') + [CompletionResult]::new('--host', 'host', [CompletionResultType]::ParameterName, 'host targets to build') + [CompletionResult]::new('--target', 'target', [CompletionResultType]::ParameterName, 'target targets to build') + [CompletionResult]::new('--exclude', 'exclude', [CompletionResultType]::ParameterName, 'build paths to exclude') + [CompletionResult]::new('--rustc-error-format', 'rustc-error-format', [CompletionResultType]::ParameterName, 'rustc-error-format') + [CompletionResult]::new('--on-fail', 'on-fail', [CompletionResultType]::ParameterName, 'command to run on failure') + [CompletionResult]::new('--stage', 'stage', [CompletionResultType]::ParameterName, 'stage to build (indicates compiler to use/test, e.g., stage 0 uses the bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)') + [CompletionResult]::new('--keep-stage', 'keep-stage', [CompletionResultType]::ParameterName, 'stage(s) to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--keep-stage-std', 'keep-stage-std', [CompletionResultType]::ParameterName, 'stage(s) of the standard library to keep without recompiling (pass multiple times to keep e.g., both stages 0 and 1)') + [CompletionResult]::new('--src', 'src', [CompletionResultType]::ParameterName, 'path to the root of the rust checkout') + [CompletionResult]::new('-j', 'j', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--jobs', 'jobs', [CompletionResultType]::ParameterName, 'number of jobs to run in parallel') + [CompletionResult]::new('--warnings', 'warnings', [CompletionResultType]::ParameterName, 'if value is deny, will deny warnings if value is warn, will emit warnings otherwise, use the default configured behaviour') + [CompletionResult]::new('--error-format', 'error-format', [CompletionResultType]::ParameterName, 'rustc error format') + [CompletionResult]::new('--color', 'color', [CompletionResultType]::ParameterName, 'whether to use color in cargo and rustc output') + [CompletionResult]::new('--llvm-skip-rebuild', 'llvm-skip-rebuild', [CompletionResultType]::ParameterName, 'whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml') + [CompletionResult]::new('--rust-profile-generate', 'rust-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with rustc build') + [CompletionResult]::new('--rust-profile-use', 'rust-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for rustc build') + [CompletionResult]::new('--llvm-profile-use', 'llvm-profile-use', [CompletionResultType]::ParameterName, 'use PGO profile for LLVM build') + [CompletionResult]::new('--llvm-bolt-profile-use', 'llvm-bolt-profile-use', [CompletionResultType]::ParameterName, 'use BOLT profile for LLVM build') + [CompletionResult]::new('--run', 'run', [CompletionResultType]::ParameterName, 'run suggested tests') + [CompletionResult]::new('-v', 'v', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('--verbose', 'verbose', [CompletionResultType]::ParameterName, 'use verbose output (-vv for very verbose)') + [CompletionResult]::new('-i', 'i', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--incremental', 'incremental', [CompletionResultType]::ParameterName, 'use incremental compilation') + [CompletionResult]::new('--include-default-paths', 'include-default-paths', [CompletionResultType]::ParameterName, 'include default paths in addition to the provided ones') + [CompletionResult]::new('--dry-run', 'dry-run', [CompletionResultType]::ParameterName, 'dry run; don''t build anything') + [CompletionResult]::new('--json-output', 'json-output', [CompletionResultType]::ParameterName, 'use message-format=json') + [CompletionResult]::new('--llvm-profile-generate', 'llvm-profile-generate', [CompletionResultType]::ParameterName, 'generate PGO profile with llvm built for rustc') + [CompletionResult]::new('--llvm-bolt-profile-generate', 'llvm-bolt-profile-generate', [CompletionResultType]::ParameterName, 'generate BOLT profile for LLVM build') + [CompletionResult]::new('-h', 'h', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + [CompletionResult]::new('--help', 'help', [CompletionResultType]::ParameterName, 'Print help (see more with ''--help'')') + break + } + }) + + $completions.Where{ $_.CompletionText -like "$wordToComplete*" } | + Sort-Object -Property ListItemText +} diff --git a/src/etc/completions/x.py.sh b/src/etc/completions/x.py.sh new file mode 100644 index 00000000000..931cc4353b2 --- /dev/null +++ b/src/etc/completions/x.py.sh @@ -0,0 +1,1644 @@ +_x.py() { + local i cur prev opts cmd + COMPREPLY=() + cur="${COMP_WORDS[COMP_CWORD]}" + prev="${COMP_WORDS[COMP_CWORD-1]}" + cmd="" + opts="" + + for i in ${COMP_WORDS[@]} + do + case "${cmd},${i}" in + ",$1") + cmd="x.py" + ;; + bootstrap,bench) + cmd="bootstrap__bench" + ;; + bootstrap,build) + cmd="bootstrap__build" + ;; + bootstrap,check) + cmd="bootstrap__check" + ;; + bootstrap,clean) + cmd="bootstrap__clean" + ;; + bootstrap,clippy) + cmd="bootstrap__clippy" + ;; + bootstrap,dist) + cmd="bootstrap__dist" + ;; + bootstrap,doc) + cmd="bootstrap__doc" + ;; + bootstrap,fix) + cmd="bootstrap__fix" + ;; + bootstrap,fmt) + cmd="bootstrap__fmt" + ;; + bootstrap,install) + cmd="bootstrap__install" + ;; + bootstrap,run) + cmd="bootstrap__run" + ;; + bootstrap,setup) + cmd="bootstrap__setup" + ;; + bootstrap,suggest) + cmd="bootstrap__suggest" + ;; + bootstrap,test) + cmd="bootstrap__test" + ;; + *) + ;; + esac + done + + case "${cmd}" in + x.py) + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]... build check clippy fix fmt doc test bench clean dist install run setup suggest" + if [[ ${cur} == -* || ${COMP_CWORD} -eq 1 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__bench) + opts="-v -i -j -h --test-args --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --test-args) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__build) + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__check) + opts="-v -i -j -h --all-targets --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__clean) + opts="-v -i -j -h --all --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__clippy) + opts="-A -D -W -F -v -i -j -h --fix --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + -A) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -D) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -W) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + -F) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__dist) + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__doc) + opts="-v -i -j -h --open --json --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__fix) + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__fmt) + opts="-v -i -j -h --check --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__install) + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__run) + opts="-v -i -j -h --args --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --args) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__setup) + opts="-v -i -j -h --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [<PROFILE>|hook|vscode|link] [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__suggest) + opts="-v -i -j -h --run --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + x.py__test) + opts="-v -i -j -h --no-fail-fast --skip --test-args --rustc-args --no-doc --doc --bless --force-rerun --only-modified --compare-mode --pass --run --rustfix-coverage --verbose --incremental --config --build-dir --build --host --target --exclude --include-default-paths --rustc-error-format --on-fail --dry-run --stage --keep-stage --keep-stage-std --src --jobs --warnings --error-format --json-output --color --llvm-skip-rebuild --rust-profile-generate --rust-profile-use --llvm-profile-use --llvm-profile-generate --llvm-bolt-profile-generate --llvm-bolt-profile-use --help [PATHS]... [ARGS]..." + if [[ ${cur} == -* || ${COMP_CWORD} -eq 2 ]] ; then + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + fi + case "${prev}" in + --skip) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --test-args) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-args) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --compare-mode) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --pass) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --run) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --config) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build-dir) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --build) + COMPREPLY=("${cur}") + return 0 + ;; + --host) + COMPREPLY=("${cur}") + return 0 + ;; + --target) + COMPREPLY=("${cur}") + return 0 + ;; + --exclude) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rustc-error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --on-fail) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage) + COMPREPLY=("${cur}") + return 0 + ;; + --keep-stage-std) + COMPREPLY=("${cur}") + return 0 + ;; + --src) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --jobs) + COMPREPLY=("${cur}") + return 0 + ;; + -j) + COMPREPLY=("${cur}") + return 0 + ;; + --warnings) + COMPREPLY=($(compgen -W "deny warn default" -- "${cur}")) + return 0 + ;; + --error-format) + COMPREPLY=("${cur}") + return 0 + ;; + --color) + COMPREPLY=($(compgen -W "always never auto" -- "${cur}")) + return 0 + ;; + --llvm-skip-rebuild) + COMPREPLY=($(compgen -W "true false" -- "${cur}")) + return 0 + ;; + --rust-profile-generate) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --rust-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + --llvm-bolt-profile-use) + COMPREPLY=($(compgen -f "${cur}")) + return 0 + ;; + *) + COMPREPLY=() + ;; + esac + COMPREPLY=( $(compgen -W "${opts}" -- "${cur}") ) + return 0 + ;; + esac +} + +complete -F _x.py -o bashdefault -o default x.py diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index b802fd065fe..17aa6b38e38 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -594,9 +594,8 @@ pub(super) fn display_macro_source( def_id: DefId, vis: ty::Visibility<DefId>, ) -> String { - let tts: Vec<_> = def.body.tokens.clone().into_trees().collect(); // Extract the spans of all matchers. They represent the "interface" of the macro. - let matchers = tts.chunks(4).map(|arm| &arm[0]); + let matchers = def.body.tokens.chunks(4).map(|arm| &arm[0]); if def.macro_rules { format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx.tcx, matchers, ";")) diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 4b0aee9c3ad..09e7ed293d4 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -551,7 +551,15 @@ impl<'a, I: Iterator<Item = Event<'a>>> SummaryLine<'a, I> { } fn check_if_allowed_tag(t: &Tag<'_>) -> bool { - matches!(t, Tag::Paragraph | Tag::Emphasis | Tag::Strong | Tag::Link(..) | Tag::BlockQuote) + matches!( + t, + Tag::Paragraph + | Tag::Emphasis + | Tag::Strong + | Tag::Strikethrough + | Tag::Link(..) + | Tag::BlockQuote + ) } fn is_forbidden_tag(t: &Tag<'_>) -> bool { @@ -773,7 +781,7 @@ impl<'tcx> ExtraInfo<'tcx> { ExtraInfo { def_id, sp, tcx } } - fn error_invalid_codeblock_attr(&self, msg: &str, help: &str) { + fn error_invalid_codeblock_attr(&self, msg: String, help: &str) { if let Some(def_id) = self.def_id.as_local() { self.tcx.struct_span_lint_hir( crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, @@ -948,7 +956,7 @@ impl LangString { } { if let Some(extra) = extra { extra.error_invalid_codeblock_attr( - &format!("unknown attribute `{}`. Did you mean `{}`?", x, flag), + format!("unknown attribute `{}`. Did you mean `{}`?", x, flag), help, ); } diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index d6773169639..0a2f5f6653c 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1751,7 +1751,7 @@ fn render_impl( if trait_.is_none() && i.inner_impl().items.is_empty() { w.write_str( "<div class=\"item-info\">\ - <div class=\"stab empty-impl\">This impl block contains no items.</div> + <div class=\"stab empty-impl\">This impl block contains no items.</div>\ </div>", ); } diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index b6eb450d62b..0a56916edcd 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -192,11 +192,11 @@ fn init_logging() { Ok("auto") | Err(VarError::NotPresent) => io::stdout().is_terminal(), Ok(value) => early_error( ErrorOutputType::default(), - &format!("invalid log color value '{}': expected one of always, never, or auto", value), + format!("invalid log color value '{}': expected one of always, never, or auto", value), ), Err(VarError::NotUnicode(value)) => early_error( ErrorOutputType::default(), - &format!( + format!( "invalid log color value '{}': expected one of always, never, or auto", value.to_string_lossy() ), @@ -228,7 +228,7 @@ fn get_args() -> Option<Vec<String>> { .map_err(|arg| { early_warn( ErrorOutputType::default(), - &format!("Argument {} is not valid Unicode: {:?}", i, arg), + format!("Argument {} is not valid Unicode: {:?}", i, arg), ); }) .ok() @@ -721,7 +721,7 @@ fn main_args(at_args: &[String]) -> MainResult { let matches = match options.parse(&args[1..]) { Ok(m) => m, Err(err) => { - early_error(ErrorOutputType::default(), &err.to_string()); + early_error(ErrorOutputType::default(), err.to_string()); } }; @@ -739,6 +739,9 @@ fn main_args(at_args: &[String]) -> MainResult { } }; + // Set parallel mode before error handler creation, which will create `Lock`s. + interface::set_thread_safe_mode(&options.unstable_opts); + let diag = core::new_handler( options.error_format, None, diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index a885ff0ca5e..9381b3e0567 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -8,7 +8,7 @@ use rustc_data_structures::{ fx::{FxHashMap, FxHashSet}, intern::Interned, }; -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticMessage}; use rustc_hir::def::Namespace::*; use rustc_hir::def::{DefKind, Namespace, PerNS}; use rustc_hir::def_id::{DefId, CRATE_DEF_ID}; @@ -24,6 +24,7 @@ use rustc_span::BytePos; use smallvec::{smallvec, SmallVec}; use std::borrow::Cow; +use std::fmt::Display; use std::mem; use std::ops::Range; @@ -841,7 +842,7 @@ impl PreprocessingError { match self { PreprocessingError::MultipleAnchors => report_multiple_anchors(cx, diag_info), PreprocessingError::Disambiguator(range, msg) => { - disambiguator_error(cx, diag_info, range.clone(), msg) + disambiguator_error(cx, diag_info, range.clone(), msg.as_str()) } PreprocessingError::MalformedGenerics(err, path_str) => { report_malformed_generics(cx, diag_info, *err, path_str) @@ -1185,7 +1186,7 @@ impl LinkCollector<'_, '_> { } suggest_disambiguator(resolved, diag, path_str, &ori_link.link, sp); }; - report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, diag_info, callback); + report_diagnostic(self.cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, callback); } fn report_rawptr_assoc_feature_gate(&self, dox: &str, ori_link: &Range<usize>, item: &Item) { @@ -1581,7 +1582,7 @@ impl Suggestion { fn report_diagnostic( tcx: TyCtxt<'_>, lint: &'static Lint, - msg: &str, + msg: impl Into<DiagnosticMessage> + Display, DiagnosticInfo { item, ori_link: _, dox, link_range }: &DiagnosticInfo<'_>, decorate: impl FnOnce(&mut Diagnostic, Option<rustc_span::Span>), ) { @@ -1649,7 +1650,7 @@ fn resolution_failure( report_diagnostic( tcx, BROKEN_INTRA_DOC_LINKS, - &format!("unresolved link to `{}`", path_str), + format!("unresolved link to `{}`", path_str), &diag_info, |diag, sp| { let item = |res: Res| format!("the {} `{}`", res.descr(), res.name(tcx),); @@ -1865,20 +1866,20 @@ fn resolution_failure( fn report_multiple_anchors(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>) { let msg = format!("`{}` contains multiple anchors", diag_info.ori_link); - anchor_failure(cx, diag_info, &msg, 1) + anchor_failure(cx, diag_info, msg, 1) } fn report_anchor_conflict(cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, def_id: DefId) { let (link, kind) = (diag_info.ori_link, Res::from_def_id(cx.tcx, def_id).descr()); let msg = format!("`{link}` contains an anchor, but links to {kind}s are already anchored"); - anchor_failure(cx, diag_info, &msg, 0) + anchor_failure(cx, diag_info, msg, 0) } /// Report an anchor failure. fn anchor_failure( cx: &DocContext<'_>, diag_info: DiagnosticInfo<'_>, - msg: &str, + msg: String, anchor_idx: usize, ) { report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, sp| { @@ -1898,7 +1899,7 @@ fn disambiguator_error( cx: &DocContext<'_>, mut diag_info: DiagnosticInfo<'_>, disambiguator_range: Range<usize>, - msg: &str, + msg: impl Into<DiagnosticMessage> + Display, ) { diag_info.link_range = disambiguator_range; report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, &diag_info, |diag, _sp| { @@ -1919,7 +1920,7 @@ fn report_malformed_generics( report_diagnostic( cx.tcx, BROKEN_INTRA_DOC_LINKS, - &format!("unresolved link to `{}`", path_str), + format!("unresolved link to `{}`", path_str), &diag_info, |diag, sp| { let note = match err { @@ -1994,7 +1995,7 @@ fn ambiguity_error( } } - report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, &msg, diag_info, |diag, sp| { + report_diagnostic(cx.tcx, BROKEN_INTRA_DOC_LINKS, msg, diag_info, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "ambiguous link"); } else { @@ -2046,7 +2047,7 @@ fn privacy_error(cx: &DocContext<'_>, diag_info: &DiagnosticInfo<'_>, path_str: let msg = format!("public documentation for `{}` links to private item `{}`", item_name, path_str); - report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, &msg, diag_info, |diag, sp| { + report_diagnostic(cx.tcx, PRIVATE_INTRA_DOC_LINKS, msg, diag_info, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "this item is private"); } diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index deb29b1e7a9..8f8dc6b7090 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -5,7 +5,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId, LocalDefIdSet}; -use rustc_hir::intravisit::{walk_item, Visitor}; +use rustc_hir::intravisit::{walk_body, walk_item, Visitor}; use rustc_hir::{Node, CRATE_HIR_ID}; use rustc_middle::hir::nested_filter; use rustc_middle::ty::TyCtxt; @@ -106,6 +106,7 @@ pub(crate) struct RustdocVisitor<'a, 'tcx> { exact_paths: DefIdMap<Vec<Symbol>>, modules: Vec<Module<'tcx>>, is_importable_from_parent: bool, + inside_body: bool, } impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { @@ -129,6 +130,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { exact_paths: Default::default(), modules: vec![om], is_importable_from_parent: true, + inside_body: false, } } @@ -368,6 +370,26 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { import_id: Option<LocalDefId>, ) { debug!("visiting item {:?}", item); + if self.inside_body { + // Only impls can be "seen" outside a body. For example: + // + // ``` + // struct Bar; + // + // fn foo() { + // impl Bar { fn bar() {} } + // } + // Bar::bar(); + // ``` + if let hir::ItemKind::Impl(impl_) = item.kind && + // Don't duplicate impls when inlining or if it's implementing a trait, we'll pick + // them up regardless of where they're located. + impl_.of_trait.is_none() + { + self.add_to_current_mod(item, None, None); + } + return; + } let name = renamed.unwrap_or(item.ident.name); let tcx = self.cx.tcx; @@ -455,7 +477,8 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { | hir::ItemKind::Union(..) | hir::ItemKind::TyAlias(..) | hir::ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::TyAlias, .. + origin: hir::OpaqueTyOrigin::TyAlias { .. }, + .. }) | hir::ItemKind::Static(..) | hir::ItemKind::Trait(..) @@ -563,4 +586,10 @@ impl<'a, 'tcx> Visitor<'tcx> for RustdocVisitor<'a, 'tcx> { fn visit_lifetime(&mut self, _: &hir::Lifetime) { // Unneeded. } + + fn visit_body(&mut self, b: &'tcx hir::Body<'tcx>) { + let prev = mem::replace(&mut self.inside_body, true); + walk_body(self, b); + self.inside_body = prev; + } } diff --git a/src/llvm-project b/src/llvm-project -Subproject ea6fa9c2d43aaf0f11559719eda9b54d356d541 +Subproject 533d3f338b804d54e5d0ac4fba6276af23002d9 diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 13413c64ff88dd6c2824e9eb9374fc5f10895d2 +Subproject 09276c703a473ab33daaeb94917232e80eefd62 diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml index b9921301197..a9d42159c4b 100644 --- a/src/tools/clippy/.github/workflows/clippy.yml +++ b/src/tools/clippy/.github/workflows/clippy.yml @@ -39,7 +39,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index 93198aabdb5..30a156c925b 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -27,7 +27,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 with: ref: ${{ github.ref }} @@ -83,7 +83,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain @@ -149,7 +149,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain @@ -173,7 +173,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain @@ -233,7 +233,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml index 14f20212add..514706d64c8 100644 --- a/src/tools/clippy/.github/workflows/clippy_dev.yml +++ b/src/tools/clippy/.github/workflows/clippy_dev.yml @@ -25,7 +25,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 # Run - name: Build diff --git a/src/tools/clippy/.github/workflows/deploy.yml b/src/tools/clippy/.github/workflows/deploy.yml index 71d71d10359..f42928c2cd1 100644 --- a/src/tools/clippy/.github/workflows/deploy.yml +++ b/src/tools/clippy/.github/workflows/deploy.yml @@ -21,10 +21,10 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 with: ref: ${{ env.TARGET_BRANCH }} path: 'out' diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml index 0bc2f49f5e9..7d25b6a2b79 100644 --- a/src/tools/clippy/.github/workflows/remark.yml +++ b/src/tools/clippy/.github/workflows/remark.yml @@ -16,10 +16,10 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Setup Node.js - uses: actions/setup-node@v1.4.4 + uses: actions/setup-node@v3 with: node-version: '14.x' diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index ebf5b58a586..79f2a47110b 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -4620,6 +4620,7 @@ Released 2018-09-13 [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else [`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop [`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum +[`empty_line_after_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_doc_comments [`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr [`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop [`empty_structs_with_brackets`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_structs_with_brackets @@ -4785,6 +4786,7 @@ Released 2018-09-13 [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy +[`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`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 @@ -4897,6 +4899,7 @@ Released 2018-09-13 [`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding [`no_mangle_with_rust_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_mangle_with_rust_abi [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal +[`non_minimal_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_minimal_cfg [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty [`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool @@ -4978,6 +4981,7 @@ Released 2018-09-13 [`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 +[`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index 6745e15c006..d712d3e6750 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -278,7 +278,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT <!-- REUSE-IgnoreStart --> -Copyright 2014-2022 The Rust Project Developers +Copyright 2014-2023 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/book/src/development/type_checking.md b/src/tools/clippy/book/src/development/type_checking.md index 225de849566..d7c2775b896 100644 --- a/src/tools/clippy/book/src/development/type_checking.md +++ b/src/tools/clippy/book/src/development/type_checking.md @@ -133,7 +133,7 @@ in this chapter: - [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html) - [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html) -[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html#variant.Adt +[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html#variant.Adt [AdtDef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html [expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty [node_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.node_type @@ -142,9 +142,9 @@ in this chapter: [kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.kind [LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html [LateLintPass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html -[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty +[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/typeck_results/struct.TypeckResults.html#method.pat_ty [Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html -[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html +[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html [middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html [hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 37e1e6a742f..98e69c7fd26 100644 --- a/src/tools/clippy/clippy_lints/Cargo.toml +++ b/src/tools/clippy/clippy_lints/Cargo.toml @@ -17,7 +17,7 @@ if_chain = "1.0" itertools = "0.10.1" pulldown-cmark = { version = "0.9", default-features = false } quine-mc_cluskey = "0.2" -regex-syntax = "0.6" +regex-syntax = "0.7" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", optional = true } tempfile = { version = "3.2", optional = true } 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 a36df55d0bd..a8dc0cb3b58 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs @@ -38,7 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { _ => return, }; let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return }; - let Some((Constant::Bool(val), _)) = constant(cx, cx.typeck_results(), condition) else { return }; + let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else { return }; if val { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 751c262673b..897495ba108 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -178,6 +178,52 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Checks for empty lines after documenation comments. + /// + /// ### Why is this bad? + /// The documentation comment was most likely meant to be an inner attribute or regular comment. + /// If it was intended to be a documentation comment, then the empty line should be removed to + /// be more idiomatic. + /// + /// ### Known problems + /// Only detects empty lines immediately following the documentation. If the doc comment is followed + /// by an attribute and then an empty line, this lint will not trigger. Use `empty_line_after_outer_attr` + /// in combination with this lint to detect both cases. + /// + /// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`). + /// + /// ### Example + /// ```rust + /// /// Some doc comment with a blank line after it. + /// + /// fn not_quite_good_code() { } + /// ``` + /// + /// Use instead: + /// ```rust + /// /// Good (no blank line) + /// fn this_is_fine() { } + /// ``` + /// + /// ```rust + /// // Good (convert to a regular comment) + /// + /// fn this_is_fine_too() { } + /// ``` + /// + /// ```rust + /// //! Good (convert to a comment on an inner attribute) + /// + /// fn this_is_fine_as_well() { } + /// ``` + #[clippy::version = "1.70.0"] + pub EMPTY_LINE_AFTER_DOC_COMMENTS, + nursery, + "empty line after documentation comments" +} + +declare_clippy_lint! { + /// ### What it does /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. /// /// ### Why is this bad? @@ -292,6 +338,30 @@ declare_clippy_lint! { "ensures that all `allow` and `expect` attributes have a reason" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `any` and `all` combinators in `cfg` with only one condition. + /// + /// ### Why is this bad? + /// If there is only one condition, no need to wrap it into `any` or `all` combinators. + /// + /// ### Example + /// ```rust + /// #[cfg(any(unix))] + /// pub struct Bar; + /// ``` + /// + /// Use instead: + /// ```rust + /// #[cfg(unix)] + /// pub struct Bar; + /// ``` + #[clippy::version = "1.71.0"] + pub NON_MINIMAL_CFG, + style, + "ensure that all `cfg(any())` and `cfg(all())` have more than one condition" +} + declare_lint_pass!(Attributes => [ ALLOW_ATTRIBUTES_WITHOUT_REASON, INLINE_ALWAYS, @@ -604,6 +674,8 @@ impl_lint_pass!(EarlyAttributes => [ DEPRECATED_CFG_ATTR, MISMATCHED_TARGET_OS, EMPTY_LINE_AFTER_OUTER_ATTR, + EMPTY_LINE_AFTER_DOC_COMMENTS, + NON_MINIMAL_CFG, ]); impl EarlyLintPass for EarlyAttributes { @@ -614,15 +686,22 @@ impl EarlyLintPass for EarlyAttributes { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { check_deprecated_cfg_attr(cx, attr, &self.msrv); check_mismatched_target_os(cx, attr); + check_minimal_cfg_condition(cx, attr); } extract_msrv_attr!(EarlyContext); } +/// Check for empty lines after outer attributes. +/// +/// Attributes and documenation comments are both considered outer attributes +/// by the AST. However, the average user likely considers them to be different. +/// Checking for empty lines after each of these attributes is split into two different +/// lints but can share the same logic. fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { let mut iter = item.attrs.iter().peekable(); while let Some(attr) = iter.next() { - if matches!(attr.kind, AttrKind::Normal(..)) + if (matches!(attr.kind, AttrKind::Normal(..)) || matches!(attr.kind, AttrKind::DocComment(..))) && attr.style == AttrStyle::Outer && is_present_in_source(cx, attr.span) { @@ -639,13 +718,20 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It let lines = without_block_comments(lines); if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 { - span_lint( - cx, - EMPTY_LINE_AFTER_OUTER_ATTR, - begin_of_attr_to_item, - "found an empty line after an outer attribute. \ - Perhaps you forgot to add a `!` to make it an inner attribute?", - ); + let (lint_msg, lint_type) = match attr.kind { + AttrKind::DocComment(..) => ( + "found an empty line after a doc comment. \ + Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?", + EMPTY_LINE_AFTER_DOC_COMMENTS, + ), + AttrKind::Normal(..) => ( + "found an empty line after an outer attribute. \ + Perhaps you forgot to add a `!` to make it an inner attribute?", + EMPTY_LINE_AFTER_OUTER_ATTR, + ), + }; + + span_lint(cx, lint_type, begin_of_attr_to_item, lint_msg); } } } @@ -690,6 +776,48 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msr } } +fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { + for item in items.iter() { + if let NestedMetaItem::MetaItem(meta) = item { + if !meta.has_name(sym::any) && !meta.has_name(sym::all) { + continue; + } + if let MetaItemKind::List(list) = &meta.kind { + check_nested_cfg(cx, list); + if list.len() == 1 { + span_lint_and_then( + cx, + NON_MINIMAL_CFG, + meta.span, + "unneeded sub `cfg` when there is only one condition", + |diag| { + if let Some(snippet) = snippet_opt(cx, list[0].span()) { + diag.span_suggestion(meta.span, "try", snippet, Applicability::MaybeIncorrect); + } + }, + ); + } else if list.is_empty() && meta.has_name(sym::all) { + span_lint_and_then( + cx, + NON_MINIMAL_CFG, + meta.span, + "unneeded sub `cfg` when there is no condition", + |_| {}, + ); + } + } + } + } +} + +fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) { + if attr.has_name(sym::cfg) && + let Some(items) = attr.meta_item_list() + { + check_nested_cfg(cx, &items); + } +} + fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { fn find_os(name: &str) -> Option<&'static str> { UNIX_SYSTEMS diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs index c4520d00392..814108ed8a7 100644 --- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs +++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs @@ -1,5 +1,6 @@ use crate::reference::DEREF_ADDROF; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use clippy_utils::{get_parent_expr, is_lint_allowed}; @@ -47,8 +48,8 @@ declare_clippy_lint! { declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]); -impl LateLintPass<'_> for BorrowDerefRef { - fn check_expr(&mut self, cx: &LateContext<'_>, e: &rustc_hir::Expr<'_>) { +impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef { + fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) { if_chain! { if !e.span.from_expansion(); if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind; @@ -58,6 +59,7 @@ impl LateLintPass<'_> for BorrowDerefRef { if !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..) ); let ref_ty = cx.typeck_results().expr_ty(deref_target); if let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind(); + if !is_from_proc_macro(cx, e); then{ if let Some(parent_expr) = get_parent_expr(cx, e){ diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index dfa949d1af2..e42c3fe2432 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -8,7 +8,9 @@ use rustc_hir::{ Block, Expr, ExprKind, Local, Node, QPath, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::{lint::in_external_macro, ty::print::with_forced_trimmed_paths}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::print::with_forced_trimmed_paths; +use rustc_middle::ty::IsSuggestable; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -49,7 +51,6 @@ impl LateLintPass<'_> for BoxDefault { && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box()) && is_default_equivalent(cx, arg) { - let arg_ty = cx.typeck_results().expr_ty(arg); span_lint_and_sugg( cx, BOX_DEFAULT, @@ -58,8 +59,10 @@ impl LateLintPass<'_> for BoxDefault { "try", if is_plain_default(arg_path) || given_type(cx, expr) { "Box::default()".into() - } else { + } else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) { with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()")) + } else { + return }, Applicability::MachineApplicable ); diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs index 322dc41b3a1..da756129db3 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs @@ -21,8 +21,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, fn is_known_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { match constant(cx, cx.typeck_results(), e) { - Some((Constant::F64(n), _)) => n.is_nan(), - Some((Constant::F32(n), _)) => n.is_nan(), + Some(Constant::F64(n)) => n.is_nan(), + Some(Constant::F32(n)) => n.is_nan(), _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index 95c2ecbf791..84b99ad5c24 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -15,7 +15,7 @@ use rustc_target::abi::IntegerType; use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION}; fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> { - if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) { + if let Some(Constant::Int(c)) = constant(cx, cx.typeck_results(), expr) { Some(c) } else { None 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 a20a97d4e56..a83dfd94dc2 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 @@ -29,7 +29,7 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast // Don't lint for positive constants. let const_val = constant(cx, cx.typeck_results(), cast_op); if_chain! { - if let Some((Constant::Int(n), _)) = const_val; + if let Some(Constant::Int(n)) = const_val; if let ty::Int(ity) = *cast_from.kind(); if sext(cx.tcx, n, ity) >= 0; then { diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index 799e71e847a..ea17e7a6071 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -3,10 +3,10 @@ use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_hir::{Expr, ExprKind, Node}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::sym; +use rustc_span::{sym, BytePos, Pos, Span}; declare_clippy_lint! { /// ### What it does @@ -31,6 +31,31 @@ declare_clippy_lint! { "`dbg!` macro is intended as a debugging tool" } +/// Gets the span of the statement up to the next semicolon, if and only if the next +/// non-whitespace character actually is a semicolon. +/// E.g. +/// ```rust,ignore +/// +/// dbg!(); +/// ^^^^^^^ this span is returned +/// +/// foo!(dbg!()); +/// no span is returned +/// ``` +fn span_including_semi(cx: &LateContext<'_>, span: Span) -> Option<Span> { + let sm = cx.sess().source_map(); + let sf = sm.lookup_source_file(span.hi()); + let src = sf.src.as_ref()?.get(span.hi().to_usize()..)?; + let first_non_whitespace = src.find(|c: char| !c.is_whitespace())?; + + if src.as_bytes()[first_non_whitespace] == b';' { + let hi = span.hi() + BytePos::from_usize(first_non_whitespace + 1); + Some(span.with_hi(hi)) + } else { + None + } +} + #[derive(Copy, Clone)] pub struct DbgMacro { allow_dbg_in_tests: bool, @@ -55,13 +80,25 @@ impl LateLintPass<'_> for DbgMacro { return; } let mut applicability = Applicability::MachineApplicable; - let suggestion = match expr.peel_drop_temps().kind { + + let (sugg_span, suggestion) = match expr.peel_drop_temps().kind { // dbg!() - ExprKind::Block(_, _) => String::new(), - // dbg!(1) - ExprKind::Match(val, ..) => { - snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string() + ExprKind::Block(..) => { + // If the `dbg!` macro is a "free" statement and not contained within other expressions, + // remove the whole statement. + if let Some(Node::Stmt(stmt)) = cx.tcx.hir().find_parent(expr.hir_id) + && let Some(span) = span_including_semi(cx, stmt.span.source_callsite()) + { + (span, String::new()) + } else { + (macro_call.span, String::from("()")) + } }, + // dbg!(1) + ExprKind::Match(val, ..) => ( + macro_call.span, + snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string(), + ), // dbg!(2, 3) ExprKind::Tup( [ @@ -82,7 +119,7 @@ impl LateLintPass<'_> for DbgMacro { "..", &mut applicability, ); - format!("({snippet})") + (macro_call.span, format!("({snippet})")) }, _ => return, }; @@ -90,7 +127,7 @@ impl LateLintPass<'_> for DbgMacro { span_lint_and_sugg( cx, DBG_MACRO, - macro_call.span, + sugg_span, "the `dbg!` macro is intended as a debugging tool", "remove the invocation before committing it to a version control system", suggestion, diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index 79d0f6f3607..423eee47742 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -48,9 +48,11 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::attrs::BLANKET_CLIPPY_RESTRICTION_LINTS_INFO, crate::attrs::DEPRECATED_CFG_ATTR_INFO, crate::attrs::DEPRECATED_SEMVER_INFO, + crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::attrs::INLINE_ALWAYS_INFO, crate::attrs::MISMATCHED_TARGET_OS_INFO, + crate::attrs::NON_MINIMAL_CFG_INFO, crate::attrs::USELESS_ATTRIBUTE_INFO, crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO, crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO, @@ -132,12 +134,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::doc::NEEDLESS_DOCTEST_MAIN_INFO, crate::doc::UNNECESSARY_SAFETY_DOC_INFO, crate::double_parens::DOUBLE_PARENS_INFO, - crate::drop_forget_ref::DROP_COPY_INFO, crate::drop_forget_ref::DROP_NON_DROP_INFO, - crate::drop_forget_ref::DROP_REF_INFO, - crate::drop_forget_ref::FORGET_COPY_INFO, crate::drop_forget_ref::FORGET_NON_DROP_INFO, - crate::drop_forget_ref::FORGET_REF_INFO, crate::drop_forget_ref::UNDROPPED_MANUALLY_DROPS_INFO, crate::duplicate_mod::DUPLICATE_MOD_INFO, crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO, @@ -351,6 +349,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::ITER_WITH_DRAIN_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, + crate::methods::MANUAL_NEXT_BACK_INFO, crate::methods::MANUAL_OK_OR_INFO, crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO, crate::methods::MANUAL_SPLIT_ONCE_INFO, @@ -489,7 +488,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::operators::FLOAT_EQUALITY_WITHOUT_ABS_INFO, crate::operators::IDENTITY_OP_INFO, crate::operators::INEFFECTIVE_BIT_MASK_INFO, - crate::operators::INTEGER_ARITHMETIC_INFO, crate::operators::INTEGER_DIVISION_INFO, crate::operators::MISREFACTORED_ASSIGN_OP_INFO, crate::operators::MODULO_ARITHMETIC_INFO, @@ -539,6 +537,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::redundant_slicing::REDUNDANT_SLICING_INFO, crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO, crate::ref_option_ref::REF_OPTION_REF_INFO, + crate::ref_patterns::REF_PATTERNS_INFO, crate::reference::DEREF_ADDROF_INFO, crate::regex::INVALID_REGEX_INFO, crate::regex::TRIVIAL_REGEX_INFO, diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs index e529d81a7e9..9bd7a0dc0f3 100644 --- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs +++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs @@ -1,4 +1,4 @@ -use clippy_utils::{diagnostics::span_lint_and_sugg, is_from_proc_macro, match_def_path, paths}; +use clippy_utils::{diagnostics::span_lint_and_sugg, match_def_path, paths}; use hir::{def::Res, ExprKind}; use rustc_errors::Applicability; use rustc_hir as hir; @@ -55,7 +55,8 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs { if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind(); if def.is_struct(); if let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant(); - if !var.is_field_list_non_exhaustive() && !is_from_proc_macro(cx, expr); + if !var.is_field_list_non_exhaustive(); + if !expr.span.from_expansion() && !qpath.span().from_expansion(); then { span_lint_and_sugg( cx, diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs index 11e1bcdf12d..9c60edb1794 100644 --- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs +++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs @@ -9,102 +9,6 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for calls to `std::mem::drop` with a reference - /// instead of an owned value. - /// - /// ### Why is this bad? - /// Calling `drop` on a reference will only drop the - /// reference itself, which is a no-op. It will not call the `drop` method (from - /// the `Drop` trait implementation) on the underlying referenced value, which - /// is likely what was intended. - /// - /// ### Example - /// ```ignore - /// let mut lock_guard = mutex.lock(); - /// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex - /// // still locked - /// operation_that_requires_mutex_to_be_unlocked(); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub DROP_REF, - correctness, - "calls to `std::mem::drop` with a reference instead of an owned value" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `std::mem::forget` with a reference - /// instead of an owned value. - /// - /// ### Why is this bad? - /// Calling `forget` on a reference will only forget the - /// reference itself, which is a no-op. It will not forget the underlying - /// referenced - /// value, which is likely what was intended. - /// - /// ### Example - /// ```rust - /// let x = Box::new(1); - /// std::mem::forget(&x) // Should have been forget(x), x will still be dropped - /// ``` - #[clippy::version = "pre 1.29.0"] - pub FORGET_REF, - correctness, - "calls to `std::mem::forget` with a reference instead of an owned value" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `std::mem::drop` with a value - /// that derives the Copy trait - /// - /// ### Why is this bad? - /// Calling `std::mem::drop` [does nothing for types that - /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the - /// value will be copied and moved into the function on invocation. - /// - /// ### Example - /// ```rust - /// let x: i32 = 42; // i32 implements Copy - /// std::mem::drop(x) // A copy of x is passed to the function, leaving the - /// // original unaffected - /// ``` - #[clippy::version = "pre 1.29.0"] - pub DROP_COPY, - correctness, - "calls to `std::mem::drop` with a value that implements Copy" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `std::mem::forget` with a value that - /// derives the Copy trait - /// - /// ### Why is this bad? - /// Calling `std::mem::forget` [does nothing for types that - /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the - /// value will be copied and moved into the function on invocation. - /// - /// An alternative, but also valid, explanation is that Copy types do not - /// implement - /// the Drop trait, which means they have no destructors. Without a destructor, - /// there - /// is nothing for `std::mem::forget` to ignore. - /// - /// ### Example - /// ```rust - /// let x: i32 = 42; // i32 implements Copy - /// std::mem::forget(x) // A copy of x is passed to the function, leaving the - /// // original unaffected - /// ``` - #[clippy::version = "pre 1.29.0"] - pub FORGET_COPY, - correctness, - "calls to `std::mem::forget` with a value that implements Copy" -} - -declare_clippy_lint! { - /// ### What it does /// Checks for calls to `std::mem::drop` with a value that does not implement `Drop`. /// /// ### Why is this bad? @@ -172,24 +76,12 @@ declare_clippy_lint! { "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value" } -const DROP_REF_SUMMARY: &str = "calls to `std::mem::drop` with a reference instead of an owned value. \ - Dropping a reference does nothing"; -const FORGET_REF_SUMMARY: &str = "calls to `std::mem::forget` with a reference instead of an owned value. \ - Forgetting a reference does nothing"; -const DROP_COPY_SUMMARY: &str = "calls to `std::mem::drop` with a value that implements `Copy`. \ - Dropping a copy leaves the original intact"; -const FORGET_COPY_SUMMARY: &str = "calls to `std::mem::forget` with a value that implements `Copy`. \ - Forgetting a copy leaves the original intact"; const DROP_NON_DROP_SUMMARY: &str = "call to `std::mem::drop` with a value that does not implement `Drop`. \ Dropping such a type only extends its contained lifetimes"; const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value that does not implement `Drop`. \ Forgetting such a type is the same as dropping it"; declare_lint_pass!(DropForgetRef => [ - DROP_REF, - FORGET_REF, - DROP_COPY, - FORGET_COPY, DROP_NON_DROP, FORGET_NON_DROP, UNDROPPED_MANUALLY_DROPS @@ -206,10 +98,11 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef { let is_copy = is_copy(cx, arg_ty); let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr); let (lint, msg) = match fn_name { - sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => (DROP_REF, DROP_REF_SUMMARY), - sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY), - sym::mem_drop if is_copy && !drop_is_single_call_in_arm => (DROP_COPY, DROP_COPY_SUMMARY), - sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY), + // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, forgetting_copy_types + sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return, + sym::mem_forget if arg_ty.is_ref() => return, + sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return, + sym::mem_forget if is_copy => return, sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => { span_lint_and_help( cx, 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 a1a2c398a8a..3c55a563af4 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -114,7 +114,7 @@ declare_lint_pass!(FloatingPointArithmetic => [ // Returns the specialized log method for a given base if base is constant // and is one of 2, 10 and e fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>) -> Option<&'static str> { - if let Some((value, _)) = constant(cx, cx.typeck_results(), base) { + if let Some(value) = constant(cx, cx.typeck_results(), base) { if F32(2.0) == value || F64(2.0) == value { return Some("log2"); } else if F32(10.0) == value || F64(10.0) == value { @@ -193,8 +193,8 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { constant(cx, cx.typeck_results(), lhs), constant(cx, cx.typeck_results(), rhs), ) { - (Some((value, _)), _) if F32(1.0) == value || F64(1.0) == value => rhs, - (_, Some((value, _))) if F32(1.0) == value || F64(1.0) == value => lhs, + (Some(value), _) if F32(1.0) == value || F64(1.0) == value => rhs, + (_, Some(value)) if F32(1.0) == value || F64(1.0) == value => lhs, _ => return, }; @@ -237,7 +237,7 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> { fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver - if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) { + if let Some(value) = constant(cx, cx.typeck_results(), receiver) { if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { Some("exp") } else if F32(2.0) == value || F64(2.0) == value { @@ -258,7 +258,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: } // Check argument - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { + if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) { let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( SUBOPTIMAL_FLOPS, @@ -298,7 +298,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: } fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { + if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) { if value == Int(2) { if let Some(parent) = get_parent_expr(cx, expr) { if let Some(grandparent) = get_parent_expr(cx, parent) { @@ -384,8 +384,8 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> { _ ) = &add_rhs.kind; if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; - if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), largs_1); - if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), rargs_1); + if let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1); + if let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1); if Int(2) == lvalue && Int(2) == rvalue; then { return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, ".."))); @@ -416,7 +416,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind; if cx.typeck_results().expr_ty(lhs).is_floating_point(); - if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs); + if let Some(value) = constant(cx, cx.typeck_results(), rhs); if F32(1.0) == value || F64(1.0) == value; if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind; if cx.typeck_results().expr_ty(self_arg).is_floating_point(); @@ -669,8 +669,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { mul_lhs, mul_rhs, ) = &div_lhs.kind; - if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), div_rhs); - if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), mul_rhs); + if let Some(rvalue) = constant(cx, cx.typeck_results(), div_rhs); + if let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs); then { // TODO: also check for constant values near PI/180 or 180/PI if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && diff --git a/src/tools/clippy/clippy_lints/src/fn_null_check.rs b/src/tools/clippy/clippy_lints/src/fn_null_check.rs index d8f4a5fe221..521045a9fed 100644 --- a/src/tools/clippy/clippy_lints/src/fn_null_check.rs +++ b/src/tools/clippy/clippy_lints/src/fn_null_check.rs @@ -89,11 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for FnNullCheck { // Catching: // (fn_ptr as *<const/mut> <ty>) == <const that evaluates to null_ptr> - _ if matches!( - constant(cx, cx.typeck_results(), to_check), - Some((Constant::RawPtr(0), _)) - ) => - { + _ if matches!(constant(cx, cx.typeck_results(), to_check), Some(Constant::RawPtr(0))) => { lint_expr(cx, expr); }, diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs index 012aa5a1d1d..ee7973b82ab 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs @@ -101,10 +101,10 @@ fn get_int_max(ty: Ty<'_>) -> Option<u128> { fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, BinOpKind, &'tcx Expr<'tcx>)> { if let ExprKind::Binary(op, l, r) = expr.kind { let tr = cx.typeck_results(); - if let Some((Constant::Int(c), _)) = constant(cx, tr, r) { + if let Some(Constant::Int(c)) = constant(cx, tr, r) { return Some((c, op.node, l)); }; - if let Some((Constant::Int(c), _)) = constant(cx, tr, l) { + if let Some(Constant::Int(c)) = constant(cx, tr, l) { return Some((c, invert_op(op.node)?, r)); } } diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs index bdeddf44df7..7a269e98ff1 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -254,7 +254,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { let parent_id = map.parent_id(expr.hir_id); if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id); if let hir::ExprKind::Index(_, index_expr) = parent_expr.kind; - if let Some((Constant::Int(index_value), _)) = constant(cx, cx.typeck_results(), index_expr); + if let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr); if let Ok(index_value) = index_value.try_into(); if index_value < max_suggested_slice; diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index 924a361c0f6..22c14d9b04d 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -191,18 +191,14 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { /// Returns a tuple of options with the start and end (exclusive) values of /// the range. If the start or end is not constant, None is returned. fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u128) -> (Option<u128>, Option<u128>) { - let s = range - .start - .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c)); + let s = range.start.map(|expr| constant(cx, cx.typeck_results(), expr)); let start = match s { Some(Some(Constant::Int(x))) => Some(x), Some(_) => None, None => Some(0), }; - let e = range - .end - .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c)); + let e = range.end.map(|expr| constant(cx, cx.typeck_results(), expr)); let end = match e { Some(Some(Constant::Int(x))) => { if range.limits == RangeLimits::Closed { diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 16772a9d598..e6614180920 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -1,10 +1,12 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_from_proc_macro; use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type}; use clippy_utils::{is_must_use_func_call, paths}; -use rustc_hir::{ExprKind, Local, PatKind}; +use rustc_hir::{Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::IsSuggestable; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::{BytePos, Span}; @@ -138,7 +140,7 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [ ]; impl<'tcx> LateLintPass<'tcx> for LetUnderscore { - fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &Local<'tcx>) { if !in_external_macro(cx.tcx.sess, local.span) && let PatKind::Wild = local.pat.kind && let Some(init) = local.init @@ -191,15 +193,17 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if local.pat.default_binding_modes && local.ty.is_none() { // When `default_binding_modes` is true, the `let` keyword is present. - // Ignore function calls that return impl traits... - if let Some(init) = local.init && - matches!(init.kind, ExprKind::Call(_, _) | ExprKind::MethodCall(_, _, _, _)) { - let expr_ty = cx.typeck_results().expr_ty(init); - if expr_ty.is_impl_trait() { - return; - } - } + // Ignore unnameable types + if let Some(init) = local.init + && !cx.typeck_results().expr_ty(init).is_suggestable(cx.tcx, true) + { + return; + } + // Ignore if it is from a procedural macro... + if is_from_proc_macro(cx, init) { + return; + } span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index 3517842a01e..b442a4ac5f6 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -266,6 +266,7 @@ mod redundant_pub_crate; mod redundant_slicing; mod redundant_static_lifetimes; mod ref_option_ref; +mod ref_patterns; mod reference; mod regex; mod return_self_not_must_use; @@ -331,8 +332,11 @@ mod zero_div_zero; mod zero_sized_map_values; // end lints modules, do not remove this comment, it’s used in `update_lints` -use crate::utils::conf::{format_error, TryConf}; pub use crate::utils::conf::{lookup_conf_file, Conf}; +use crate::utils::{ + conf::{format_error, metadata::get_configuration_metadata, TryConf}, + FindAll, +}; /// Register all pre expansion lints /// @@ -471,7 +475,22 @@ pub(crate) struct LintInfo { pub fn explain(name: &str) { let target = format!("clippy::{}", name.to_ascii_uppercase()); match declared_lints::LINTS.iter().find(|info| info.lint.name == target) { - Some(info) => print!("{}", info.explanation), + Some(info) => { + println!("{}", info.explanation); + // Check if the lint has configuration + let mdconf = get_configuration_metadata(); + if let Some(config_vec_positions) = mdconf + .iter() + .find_all(|cconf| cconf.lints.contains(&info.lint.name_lower()[8..].to_owned())) + { + // If it has, print it + println!("### Configuration for {}:\n", info.lint.name_lower()); + for position in config_vec_positions { + let conf = &mdconf[position]; + println!(" - {}: {} (default: {})", conf.name, conf.doc, conf.default); + } + } + }, None => println!("unknown lint: {name}"), } } @@ -971,6 +990,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments)); store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule)); + store.register_early_pass(|| Box::new(ref_patterns::RefPatterns)); store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs)); // add lints here, do not remove this comment, it's used in `new_lint` } diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs index bba9bb445a7..09b2032e20f 100644 --- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs +++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs @@ -25,7 +25,7 @@ declare_clippy_lint! { /// /// ### Known problems /// This lint suggests replacing `filter_map()` or `flat_map()` applied to a `Lines` - /// instance in all cases. There two cases where the suggestion might not be + /// instance in all cases. There are two cases where the suggestion might not be /// appropriate or necessary: /// /// - If the `Lines` instance can never produce any error, or if an error is produced diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs index 1247370b74a..3f8b42ffe80 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -38,7 +38,6 @@ declare_clippy_lint! { /// Could be written: /// /// ```rust - /// # #![feature(let_else)] /// # fn main () { /// # let w = Some(0); /// let Some(v) = w else { return }; @@ -69,29 +68,23 @@ impl_lint_pass!(ManualLetElse => [MANUAL_LET_ELSE]); impl<'tcx> LateLintPass<'tcx> for ManualLetElse { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) { - let if_let_or_match = if_chain! { - if self.msrv.meets(msrvs::LET_ELSE); - if !in_external_macro(cx.sess(), stmt.span); - if let StmtKind::Local(local) = stmt.kind; - if let Some(init) = local.init; - if local.els.is_none(); - if local.ty.is_none(); - if init.span.ctxt() == stmt.span.ctxt(); - if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init); - then { - if_let_or_match - } else { - return; - } - }; + if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) { + return; + } + if let StmtKind::Local(local) = stmt.kind && + let Some(init) = local.init && + local.els.is_none() && + local.ty.is_none() && + init.span.ctxt() == stmt.span.ctxt() && + let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init) { match if_let_or_match { IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! { if expr_is_simple_identity(let_pat, if_then); if let Some(if_else) = if_else; if expr_diverges(cx, if_else); then { - emit_manual_let_else(cx, stmt.span, if_let_expr, let_pat, if_else); + emit_manual_let_else(cx, stmt.span, if_let_expr, local.pat, let_pat, if_else); } }, IfLetOrMatch::Match(match_expr, arms, source) => { @@ -128,15 +121,23 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse { return; } - emit_manual_let_else(cx, stmt.span, match_expr, pat_arm.pat, diverging_arm.body); + emit_manual_let_else(cx, stmt.span, match_expr, local.pat, pat_arm.pat, diverging_arm.body); }, } + }; } extract_msrv_attr!(LateContext); } -fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: &Pat<'_>, else_body: &Expr<'_>) { +fn emit_manual_let_else( + cx: &LateContext<'_>, + span: Span, + expr: &Expr<'_>, + local: &Pat<'_>, + pat: &Pat<'_>, + else_body: &Expr<'_>, +) { span_lint_and_then( cx, MANUAL_LET_ELSE, @@ -145,12 +146,11 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: |diag| { // This is far from perfect, for example there needs to be: // * mut additions for the bindings - // * renamings of the bindings + // * renamings of the bindings for `PatKind::Or` // * unused binding collision detection with existing ones // * putting patterns with at the top level | inside () // for this to be machine applicable. let mut app = Applicability::HasPlaceholders; - let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app); let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app); let (sn_else, _) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app); @@ -159,10 +159,21 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: } else { format!("{{ {sn_else} }}") }; - let sn_bl = if matches!(pat.kind, PatKind::Or(..)) { - format!("({sn_pat})") - } else { - sn_pat.into_owned() + let sn_bl = match pat.kind { + PatKind::Or(..) => { + let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app); + format!("({sn_pat})") + }, + // Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`. + PatKind::TupleStruct(ref w, args, ..) if args.len() == 1 => { + let sn_wrapper = cx.sess().source_map().span_to_snippet(w.span()).unwrap_or_default(); + let (sn_inner, _) = snippet_with_context(cx, local.span, span.ctxt(), "", &mut app); + format!("{sn_wrapper}({sn_inner})") + }, + _ => { + let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app); + sn_pat.into_owned() + }, }; let sugg = format!("let {sn_bl} = {sn_expr} else {else_bl};"); diag.span_suggestion(span, "consider writing", sugg, app); diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index 7d28c111624..93d977a5c96 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -144,7 +144,7 @@ fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx E // Returns the length of the `expr` if it's a constant string or char. fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> { - let (value, _) = constant(cx, cx.typeck_results(), expr)?; + let value = constant(cx, cx.typeck_results(), expr)?; match value { Constant::Str(value) => Some(value.len() as u128), Constant::Char(value) => Some(value.len_utf8() as u128), diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs index 33bc20dad6b..0064619ef89 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs @@ -1,10 +1,12 @@ +use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_lint_allowed; use clippy_utils::is_wild; use clippy_utils::source::snippet_with_applicability; use clippy_utils::span_contains_comment; use rustc_ast::{Attribute, LitKind}; use rustc_errors::Applicability; -use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat}; +use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat, PatKind, QPath}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; use rustc_span::source_map::Spanned; @@ -99,6 +101,14 @@ where } } + for arm in iter_without_last.clone() { + if let Some(pat) = arm.1 { + if !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id) && is_some(pat.kind) { + return false; + } + } + } + // The suggestion may be incorrect, because some arms can have `cfg` attributes // evaluated into `false` and so such arms will be stripped before. let mut applicability = Applicability::MaybeIncorrect; @@ -170,3 +180,13 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option<bool> { _ => None, } } + +fn is_some(path_kind: PatKind<'_>) -> bool { + match path_kind { + PatKind::TupleStruct(QPath::Resolved(_, path), [first, ..], _) if is_wild(first) => { + let name = path.segments[0].ident; + name.name == rustc_span::sym::Some + }, + _ => false, + } +} diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index a48f4c77f85..ae8262ace96 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -282,9 +282,8 @@ impl<'a> NormalizedPat<'a> { // TODO: Handle negative integers. They're currently treated as a wild match. ExprKind::Lit(lit) => match lit.node { LitKind::Str(sym, _) => Self::LitStr(sym), - LitKind::ByteStr(ref bytes, _) => Self::LitBytes(bytes), + LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes), LitKind::Byte(val) => Self::LitInt(val.into()), - LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes), LitKind::Char(val) => Self::LitInt(val.into()), LitKind::Int(val, _) => Self::LitInt(val), LitKind::Bool(val) => Self::LitBool(val), diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index 87b63eead25..55ec9d4474f 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -25,9 +25,9 @@ mod wild_in_or_pats; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet_opt, walk_span_to_context}; -use clippy_utils::{higher, in_constant, is_span_match}; +use clippy_utils::{higher, in_constant, is_span_match, tokenize_with_text}; use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::TokenKind; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -1147,12 +1147,7 @@ fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { // Assume true. This would require either an invalid span, or one which crosses file boundaries. return true; }; - let mut pos = 0usize; - let mut iter = tokenize(&snip).map(|t| { - let start = pos; - pos += t.len as usize; - (t.kind, start..pos) - }); + let mut iter = tokenize_with_text(&snip); // Search for the token sequence [`#`, `[`, `cfg`] while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { @@ -1163,7 +1158,7 @@ fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { ) }); if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) - && matches!(iter.next(), Some((TokenKind::Ident, range)) if &snip[range.clone()] == "cfg") + && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) { return true; } diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs index ae69ca8a339..abf2525a61c 100644 --- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs @@ -34,7 +34,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) if let Arm { pat, guard: None, .. } = *arm { if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { let lhs_const = match lhs { - Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0, + Some(lhs) => constant(cx, cx.typeck_results(), lhs)?, None => { let min_val_const = ty.numeric_min_val(cx.tcx)?; let min_constant = mir::ConstantKind::from_value( @@ -45,7 +45,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) }, }; let rhs_const = match rhs { - Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0, + Some(rhs) => constant(cx, cx.typeck_results(), rhs)?, None => { let max_val_const = ty.numeric_max_val(cx.tcx)?; let max_constant = mir::ConstantKind::from_value( diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index af121f317cd..e81e09da425 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -189,73 +189,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op if arms.len() == 2 { let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); - let found_good_method = match node_pair { - ( - PatKind::TupleStruct(ref path_left, patterns_left, _), - PatKind::TupleStruct(ref path_right, patterns_right, _), - ) if patterns_left.len() == 1 && patterns_right.len() == 1 => { - if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) { - find_good_method_for_match( - cx, - arms, - path_left, - path_right, - Item::Lang(ResultOk), - Item::Lang(ResultErr), - "is_ok()", - "is_err()", - ) - .or_else(|| { - find_good_method_for_match( - cx, - arms, - path_left, - path_right, - Item::Diag(sym::IpAddr, sym!(V4)), - Item::Diag(sym::IpAddr, sym!(V6)), - "is_ipv4()", - "is_ipv6()", - ) - }) - } else { - None - } - }, - (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right)) - | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _)) - if patterns.len() == 1 => - { - if let PatKind::Wild = patterns[0].kind { - find_good_method_for_match( - cx, - arms, - path_left, - path_right, - Item::Lang(OptionSome), - Item::Lang(OptionNone), - "is_some()", - "is_none()", - ) - .or_else(|| { - find_good_method_for_match( - cx, - arms, - path_left, - path_right, - Item::Lang(PollReady), - Item::Lang(PollPending), - "is_ready()", - "is_pending()", - ) - }) - } else { - None - } - }, - _ => None, - }; - - if let Some(good_method) = found_good_method { + if let Some(good_method) = found_good_method(cx, arms, node_pair) { let span = expr.span.to(op.span); let result_expr = match &op.kind { ExprKind::AddrOf(_, _, borrowed) => borrowed, @@ -279,6 +213,127 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op } } +fn found_good_method<'a>( + cx: &LateContext<'_>, + arms: &[Arm<'_>], + node: (&PatKind<'_>, &PatKind<'_>), +) -> Option<&'a str> { + match node { + ( + PatKind::TupleStruct(ref path_left, patterns_left, _), + PatKind::TupleStruct(ref path_right, patterns_right, _), + ) if patterns_left.len() == 1 && patterns_right.len() == 1 => { + if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) { + find_good_method_for_match( + cx, + arms, + path_left, + path_right, + Item::Lang(ResultOk), + Item::Lang(ResultErr), + "is_ok()", + "is_err()", + ) + .or_else(|| { + find_good_method_for_match( + cx, + arms, + path_left, + path_right, + Item::Diag(sym::IpAddr, sym!(V4)), + Item::Diag(sym::IpAddr, sym!(V6)), + "is_ipv4()", + "is_ipv6()", + ) + }) + } else { + None + } + }, + (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right)) + | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _)) + if patterns.len() == 1 => + { + if let PatKind::Wild = patterns[0].kind { + find_good_method_for_match( + cx, + arms, + path_left, + path_right, + Item::Lang(OptionSome), + Item::Lang(OptionNone), + "is_some()", + "is_none()", + ) + .or_else(|| { + find_good_method_for_match( + cx, + arms, + path_left, + path_right, + Item::Lang(PollReady), + Item::Lang(PollPending), + "is_ready()", + "is_pending()", + ) + }) + } else { + None + } + }, + (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Wild) if patterns.len() == 1 => { + if let PatKind::Wild = patterns[0].kind { + get_good_method(cx, arms, path_left) + } else { + None + } + }, + (PatKind::Path(ref path_left), PatKind::Wild) => get_good_method(cx, arms, path_left), + _ => None, + } +} + +fn get_ident(path: &QPath<'_>) -> Option<rustc_span::symbol::Ident> { + match path { + QPath::Resolved(_, path) => { + let name = path.segments[0].ident; + Some(name) + }, + _ => None, + } +} + +fn get_good_method<'a>(cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath<'_>) -> Option<&'a str> { + if let Some(name) = get_ident(path_left) { + return match name.as_str() { + "Ok" => { + find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultOk), "is_ok()", "is_err()") + }, + "Err" => { + find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultErr), "is_err()", "is_ok()") + }, + "Some" => find_good_method_for_matches_macro( + cx, + arms, + path_left, + Item::Lang(OptionSome), + "is_some()", + "is_none()", + ), + "None" => find_good_method_for_matches_macro( + cx, + arms, + path_left, + Item::Lang(OptionNone), + "is_none()", + "is_some()", + ), + _ => None, + }; + } + None +} + #[derive(Clone, Copy)] enum Item { Lang(LangItem), @@ -289,10 +344,11 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false }; match expected_item { - Item::Lang(expected_lang_item) => { - let expected_id = cx.tcx.lang_items().require(expected_lang_item).unwrap(); - cx.tcx.parent(id) == expected_id - }, + Item::Lang(expected_lang_item) => cx + .tcx + .lang_items() + .get(expected_lang_item) + .map_or(false, |expected_id| cx.tcx.parent(id) == expected_id), Item::Diag(expected_ty, expected_variant) => { let ty = cx.typeck_results().pat_ty(pat); @@ -345,3 +401,29 @@ fn find_good_method_for_match<'a>( _ => None, } } + +fn find_good_method_for_matches_macro<'a>( + cx: &LateContext<'_>, + arms: &[Arm<'_>], + path_left: &QPath<'_>, + expected_item_left: Item, + should_be_left: &'a str, + should_be_right: &'a str, +) -> Option<&'a str> { + let first_pat = arms[0].pat; + + let body_node_pair = if is_pat_variant(cx, first_pat, path_left, expected_item_left) { + (&arms[0].body.kind, &arms[1].body.kind) + } else { + return None; + }; + + match body_node_pair { + (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) { + (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left), + (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right), + _ => None, + }, + _ => None, + } +} 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 c830958d5c8..d1609eebfdc 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 @@ -13,7 +13,7 @@ use super::ITER_NTH_ZERO; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { if_chain! { if is_trait_method(cx, expr, sym::Iterator); - if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg); + if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg); then { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( 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 64c09214a76..b631cd00cda 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 @@ -9,7 +9,7 @@ use super::ITERATOR_STEP_BY_ZERO; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) { if is_trait_method(cx, expr, sym::Iterator) { - if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg) { + if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg) { span_lint( cx, ITERATOR_STEP_BY_ZERO, diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs b/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs new file mode 100644 index 00000000000..5f3fec53827 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs @@ -0,0 +1,38 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::ty::implements_trait; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + rev_call: &'tcx Expr<'_>, + rev_recv: &'tcx Expr<'_>, +) { + let rev_recv_ty = cx.typeck_results().expr_ty(rev_recv); + + // check that the receiver of `rev` implements `DoubleEndedIterator` and + // that `rev` and `next` come from `Iterator` + if cx + .tcx + .get_diagnostic_item(sym::DoubleEndedIterator) + .map_or(false, |double_ended_iterator| { + implements_trait(cx, rev_recv_ty, double_ended_iterator, &[]) + }) + && is_trait_method(cx, rev_call, sym::Iterator) + && is_trait_method(cx, expr, sym::Iterator) + { + span_lint_and_sugg( + cx, + super::MANUAL_NEXT_BACK, + expr.span.with_lo(rev_recv.span.hi()), + "manual backwards iteration", + "use", + String::from(".next_back()"), + Applicability::MachineApplicable, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 06b88e34d24..9a594d964ab 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -45,6 +45,7 @@ mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; mod iterator_step_by_zero; +mod manual_next_back; mod manual_ok_or; mod manual_saturating_arithmetic; mod manual_str_repeat; @@ -3132,8 +3133,11 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let iterator = vec![1].into_iter(); - /// let len = iterator.clone().collect::<Vec<_>>().len(); - /// // should be + /// let len = iterator.collect::<Vec<_>>().len(); + /// ``` + /// Use instead: + /// ```rust + /// # let iterator = vec![1].into_iter(); /// let len = iterator.count(); /// ``` #[clippy::version = "1.30.0"] @@ -3193,6 +3197,29 @@ declare_clippy_lint! { "calling `drain` in order to `clear` a container" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `.rev().next()` on a `DoubleEndedIterator` + /// + /// ### Why is this bad? + /// `.next_back()` is cleaner. + /// + /// ### Example + /// ```rust + /// # let foo = [0; 10]; + /// foo.iter().rev().next(); + /// ``` + /// Use instead: + /// ```rust + /// # let foo = [0; 10]; + /// foo.iter().next_back(); + /// ``` + #[clippy::version = "1.71.0"] + pub MANUAL_NEXT_BACK, + style, + "manual reverse iteration of `DoubleEndedIterator`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3321,6 +3348,7 @@ impl_lint_pass!(Methods => [ NEEDLESS_COLLECT, SUSPICIOUS_COMMAND_ARG_SPACE, CLEAR_WITH_DRAIN, + MANUAL_NEXT_BACK, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3677,6 +3705,7 @@ impl Methods { ("iter", []) => iter_next_slice::check(cx, expr, recv2), ("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg), ("skip_while", [_]) => skip_while_next::check(cx, expr), + ("rev", [])=> manual_next_back::check(cx, expr, recv, recv2), _ => {}, } } @@ -3741,13 +3770,13 @@ impl Methods { unnecessary_sort_by::check(cx, expr, recv, arg, true); }, ("splitn" | "rsplitn", [count_arg, pat_arg]) => { - if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { + if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv); } }, ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { - if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { + if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); } }, diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs index 0b0c6adc504..6841aaf626c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -1,6 +1,5 @@ use super::NEEDLESS_COLLECT; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::higher; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection}; @@ -8,6 +7,7 @@ use clippy_utils::{ can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id, CaptureKind, }; +use clippy_utils::{fn_def_id, higher}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; @@ -16,7 +16,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; +use rustc_middle::ty::{self, AssocKind, Clause, EarlyBinder, GenericArg, GenericArgKind, PredicateKind, Ty}; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol}; @@ -32,6 +32,8 @@ pub(super) fn check<'tcx>( if let Some(parent) = get_parent_node(cx.tcx, collect_expr.hir_id) { match parent { Node::Expr(parent) => { + check_collect_into_intoiterator(cx, parent, collect_expr, call_span, iter_expr); + if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind { let mut app = Applicability::MachineApplicable; let name = name.ident.as_str(); @@ -134,6 +136,68 @@ pub(super) fn check<'tcx>( } } +/// checks for for collecting into a (generic) method or function argument +/// taking an `IntoIterator` +fn check_collect_into_intoiterator<'tcx>( + cx: &LateContext<'tcx>, + parent: &'tcx Expr<'tcx>, + collect_expr: &'tcx Expr<'tcx>, + call_span: Span, + iter_expr: &'tcx Expr<'tcx>, +) { + if let Some(id) = fn_def_id(cx, parent) { + let args = match parent.kind { + ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => args, + _ => &[], + }; + // find the argument index of the `collect_expr` in the + // function / method call + if let Some(arg_idx) = args.iter().position(|e| e.hir_id == collect_expr.hir_id).map(|i| { + if matches!(parent.kind, ExprKind::MethodCall(_, _, _, _)) { + i + 1 + } else { + i + } + }) { + // extract the input types of the function/method call + // that contains `collect_expr` + let inputs = cx + .tcx + .liberate_late_bound_regions(id, cx.tcx.fn_sig(id).subst_identity()) + .inputs(); + + // map IntoIterator generic bounds to their signature + // types and check whether the argument type is an + // `IntoIterator` + if cx + .tcx + .param_env(id) + .caller_bounds() + .into_iter() + .filter_map(|p| { + if let PredicateKind::Clause(Clause::Trait(t)) = p.kind().skip_binder() + && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) { + Some(t.self_ty()) + } else { + None + } + }) + .any(|ty| ty == inputs[arg_idx]) + { + span_lint_and_sugg( + cx, + NEEDLESS_COLLECT, + call_span.with_lo(iter_expr.span.hi()), + NEEDLESS_COLLECT_MSG, + "remove this call", + String::new(), + Applicability::MachineApplicable, + ); + } + } + } +} + /// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool` fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool { cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| { diff --git a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs index a345ec813ff..bb4cdd2a6fa 100644 --- a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs +++ b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant_context, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_lang_item; @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>( recv: &'tcx Expr<'_>, repeat_arg: &'tcx Expr<'_>, ) { - if constant_context(cx, cx.typeck_results()).expr(repeat_arg) == Some(Constant::Int(1)) { + if constant(cx, cx.typeck_results(), repeat_arg) == Some(Constant::Int(1)) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); if ty.is_str() { span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs index 91f7ce1dbe5..5ea12c44184 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -316,7 +316,7 @@ fn parse_iter_usage<'tcx>( }; }, ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { - if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) { + if let Some(Constant::Int(idx)) = constant(cx, cx.typeck_results(), idx_expr) { let span = if name.ident.as_str() == "nth" { e.span } else { diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 3752b9a946f..303f0125690 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -16,9 +16,12 @@ use rustc_span::source_map::{ExpnKind, Span}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_parent_expr, in_constant, is_integer_literal, is_no_std_crate, iter_input_pats, last_path_segment, SpanlessEq, + get_parent_expr, in_constant, is_integer_literal, is_lint_allowed, is_no_std_crate, iter_input_pats, + last_path_segment, SpanlessEq, }; +use crate::ref_patterns::REF_PATTERNS; + declare_clippy_lint! { /// ### What it does /// Checks for function arguments and let bindings denoted as @@ -162,6 +165,10 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { return; } for arg in iter_input_pats(decl, body) { + // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. + if !is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) { + return; + } if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind { span_lint( cx, @@ -180,6 +187,8 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { if let StmtKind::Local(local) = stmt.kind; if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind; if let Some(init) = local.init; + // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. + if is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id); then { let ctxt = local.span.ctxt(); let mut app = 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 71281a0b40b..62af42a3961 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -146,7 +146,7 @@ fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool { impl<'tcx> LateLintPass<'tcx> for NeedlessBool { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use self::Expression::{Bool, RetBool}; - if e.span.from_expansion() { + if e.span.from_expansion() || !span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty() { return; } if let Some(higher::If { @@ -209,8 +209,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool { } if let Some((lhs_a, a)) = fetch_assign(then) && let Some((lhs_b, b)) = fetch_assign(r#else) && - SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) && - span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty() + SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b) { let mut applicability = Applicability::MachineApplicable; let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); diff --git a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs index d29ca37eaeb..f4863600ccc 100644 --- a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -121,7 +121,7 @@ fn detect_absurd_comparison<'tcx>( fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> { let ty = cx.typeck_results().expr_ty(expr); - let cv = constant(cx, cx.typeck_results(), expr)?.0; + let cv = constant(cx, cx.typeck_results(), expr)?; let which = match (ty.kind(), cv) { (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => ExtremeType::Minimum, diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs index f72595987ee..5c240276b76 100644 --- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs +++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs @@ -21,7 +21,7 @@ const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[ ["f64", "f64"], ["std::num::Saturating", "std::num::Saturating"], ["std::num::Wrapping", "std::num::Wrapping"], - ["std::string::String", "&str"], + ["std::string::String", "str"], ]; const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"]; const INTEGER_METHODS: &[&str] = &["saturating_div", "wrapping_div", "wrapping_rem", "wrapping_rem_euclid"]; @@ -113,7 +113,7 @@ impl ArithmeticSideEffects { if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node { return Some(n) } - if let Some((Constant::Int(n), _)) = constant(cx, cx.typeck_results(), expr) { + if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) { return Some(n); } None @@ -144,8 +144,10 @@ impl ArithmeticSideEffects { ) { return; }; - let lhs_ty = cx.typeck_results().expr_ty(lhs); - let rhs_ty = cx.typeck_results().expr_ty(rhs); + let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs); + let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs); + let lhs_ty = cx.typeck_results().expr_ty(actual_lhs).peel_refs(); + let rhs_ty = cx.typeck_results().expr_ty(actual_rhs).peel_refs(); if self.has_allowed_binary(lhs_ty, rhs_ty) { return; } @@ -154,8 +156,6 @@ impl ArithmeticSideEffects { // At least for integers, shifts are already handled by the CTFE return; } - let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs); - let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs); match ( Self::literal_integer(cx, actual_lhs), Self::literal_integer(cx, actual_rhs), diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs index 1369b3e7462..1fddf0f50e3 100644 --- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs +++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs @@ -166,7 +166,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: } fn fetch_int_literal(cx: &LateContext<'_>, lit: &Expr<'_>) -> Option<u128> { - match constant(cx, cx.typeck_results(), lit)?.0 { + match constant(cx, cx.typeck_results(), lit)? { Constant::Int(n) => Some(n), _ => None, } diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs index 786ae1552ad..e18064b7061 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs @@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp } fn is_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - if let Some((value, _)) = constant(cx, cx.typeck_results(), e) { + if let Some(value) = constant(cx, cx.typeck_results(), e) { match value { Constant::F32(num) => num.is_nan(), Constant::F64(num) => num.is_nan(), diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs index 49e662cacb0..f120be13836 100644 --- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs +++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs @@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>( if op == BinOpKind::Div && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration) - && let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right) + && let Some(Constant::Int(divisor)) = constant(cx, cx.typeck_results(), right) { let suggested_fn = match (method_path.ident.as_str(), divisor) { ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis", diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs index 97ddcdb2479..15dff126be7 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant, Constant}; +use clippy_utils::consts::{constant_with_source, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_item_name; use clippy_utils::sugg::Sugg; @@ -18,9 +18,16 @@ pub(crate) fn check<'tcx>( right: &'tcx Expr<'_>, ) { if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) { - if is_allowed(cx, left) || is_allowed(cx, right) { - return; - } + let left_is_local = match constant_with_source(cx, cx.typeck_results(), left) { + Some((c, s)) if !is_allowed(&c) => s.is_local(), + Some(_) => return, + None => true, + }; + let right_is_local = match constant_with_source(cx, cx.typeck_results(), right) { + Some((c, s)) if !is_allowed(&c) => s.is_local(), + Some(_) => return, + None => true, + }; // Allow comparing the results of signum() if is_signum(cx, left) && is_signum(cx, right) { @@ -34,10 +41,7 @@ pub(crate) fn check<'tcx>( } } let is_comparing_arrays = is_array(cx, left) || is_array(cx, right); - let (lint, msg) = get_lint_and_message( - is_named_constant(cx, left) || is_named_constant(cx, right), - is_comparing_arrays, - ); + let (lint, msg) = get_lint_and_message(left_is_local && right_is_local, is_comparing_arrays); span_lint_and_then(cx, lint, expr.span, msg, |diag| { let lhs = Sugg::hir(cx, left, ".."); let rhs = Sugg::hir(cx, right, ".."); @@ -59,44 +63,33 @@ pub(crate) fn check<'tcx>( } } -fn get_lint_and_message( - is_comparing_constants: bool, - is_comparing_arrays: bool, -) -> (&'static rustc_lint::Lint, &'static str) { - if is_comparing_constants { +fn get_lint_and_message(is_local: bool, is_comparing_arrays: bool) -> (&'static rustc_lint::Lint, &'static str) { + if is_local { ( - FLOAT_CMP_CONST, + FLOAT_CMP, if is_comparing_arrays { - "strict comparison of `f32` or `f64` constant arrays" + "strict comparison of `f32` or `f64` arrays" } else { - "strict comparison of `f32` or `f64` constant" + "strict comparison of `f32` or `f64`" }, ) } else { ( - FLOAT_CMP, + FLOAT_CMP_CONST, if is_comparing_arrays { - "strict comparison of `f32` or `f64` arrays" + "strict comparison of `f32` or `f64` constant arrays" } else { - "strict comparison of `f32` or `f64`" + "strict comparison of `f32` or `f64` constant" }, ) } } -fn is_named_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - if let Some((_, res)) = constant(cx, cx.typeck_results(), expr) { - res - } else { - false - } -} - -fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - match constant(cx, cx.typeck_results(), expr) { - Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(), - Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(), - Some((Constant::Vec(vec), _)) => vec.iter().all(|f| match f { +fn is_allowed(val: &Constant) -> bool { + match val { + &Constant::F32(f) => f == 0.0 || f.is_infinite(), + &Constant::F64(f) => f == 0.0 || f.is_infinite(), + Constant::Vec(vec) => vec.iter().all(|f| match f { Constant::F32(f) => *f == 0.0 || (*f).is_infinite(), Constant::F64(f) => *f == 0.0 || (*f).is_infinite(), _ => false, diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index 19599731bd6..d63a836e73d 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -98,32 +98,6 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for integer arithmetic operations which could overflow or panic. - /// - /// Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable - /// of overflowing according to the [Rust - /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), - /// or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is - /// attempted. - /// - /// ### Why is this bad? - /// Integer overflow will trigger a panic in debug builds or will wrap in - /// release mode. Division by zero will cause a panic in either mode. In some applications one - /// wants explicitly checked, wrapping or saturating arithmetic. - /// - /// ### Example - /// ```rust - /// # let a = 0; - /// a + 1; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub INTEGER_ARITHMETIC, - restriction, - "any integer arithmetic expression which could overflow or panic" -} - -declare_clippy_lint! { - /// ### What it does /// Checks for float arithmetic. /// /// ### Why is this bad? @@ -787,7 +761,6 @@ pub struct Operators { impl_lint_pass!(Operators => [ ABSURD_EXTREME_COMPARISONS, ARITHMETIC_SIDE_EFFECTS, - INTEGER_ARITHMETIC, FLOAT_ARITHMETIC, ASSIGN_OP_PATTERN, MISREFACTORED_ASSIGN_OP, diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs index af4e74947f4..a2c3a4d8ba7 100644 --- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs @@ -40,7 +40,7 @@ struct OperandInfo { fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OperandInfo> { match constant(cx, cx.typeck_results(), operand) { - Some((Constant::Int(v), _)) => match *cx.typeck_results().expr_ty(expr).kind() { + Some(Constant::Int(v)) => match *cx.typeck_results().expr_ty(expr).kind() { ty::Int(ity) => { let value = sext(cx.tcx, v, ity); return Some(OperandInfo { @@ -58,10 +58,10 @@ fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> }, _ => {}, }, - Some((Constant::F32(f), _)) => { + Some(Constant::F32(f)) => { return Some(floating_point_operand_info(&f)); }, - Some((Constant::F64(f), _)) => { + Some(Constant::F64(f)) => { return Some(floating_point_operand_info(&f)); }, _ => {}, diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs index 77fd45b199a..102845ceed0 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -1,8 +1,6 @@ -use super::{FLOAT_ARITHMETIC, INTEGER_ARITHMETIC}; +use super::FLOAT_ARITHMETIC; use clippy_utils::consts::constant_simple; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_from_proc_macro; -use clippy_utils::is_integer_literal; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; @@ -45,31 +43,8 @@ impl Context { _ => (), } - let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); - if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() { - if is_from_proc_macro(cx, expr) { - return; - } - match op { - hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind { - hir::ExprKind::Lit(_lit) => (), - hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { - if is_integer_literal(expr, 1) { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - } - }, - _ => { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - }, - }, - _ => { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - }, - } - } else if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() { + let (_, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); + if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() { span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); self.expr_id = Some(expr.hir_id); } @@ -80,17 +55,9 @@ impl Context { return; } let ty = cx.typeck_results().expr_ty(arg); - if constant_simple(cx, cx.typeck_results(), expr).is_none() { - if ty.is_integral() { - if is_from_proc_macro(cx, expr) { - return; - } - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - } else if ty.is_floating_point() { - span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); - self.expr_id = Some(expr.hir_id); - } + if constant_simple(cx, cx.typeck_results(), expr).is_none() && ty.is_floating_point() { + span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); + self.expr_id = Some(expr.hir_id); } } 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 bbbcda069c5..aa6d4004268 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 @@ -122,7 +122,7 @@ fn try_get_option_occurrence<'tcx>( ExprKind::Unary(UnOp::Deref, inner_expr) | ExprKind::AddrOf(_, _, inner_expr) => inner_expr, _ => expr, }; - let inner_pat = try_get_inner_pat(cx, pat)?; + let (inner_pat, is_result) = try_get_inner_pat_and_is_result(cx, pat)?; if_chain! { if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind; if let Some(some_captures) = can_move_expr_to_closure(cx, if_then); @@ -176,7 +176,7 @@ fn try_get_option_occurrence<'tcx>( ), none_expr: format!( "{}{}", - if method_sugg == "map_or" { "" } else { "|| " }, + if method_sugg == "map_or" { "" } else if is_result { "|_| " } else { "|| "}, Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app), ), }); @@ -186,11 +186,13 @@ fn try_get_option_occurrence<'tcx>( None } -fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&'tcx Pat<'tcx>> { +fn try_get_inner_pat_and_is_result<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<(&'tcx Pat<'tcx>, bool)> { if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind { let res = cx.qpath_res(qpath, pat.hir_id); - if is_res_lang_ctor(cx, res, OptionSome) || is_res_lang_ctor(cx, res, ResultOk) { - return Some(inner_pat); + if is_res_lang_ctor(cx, res, OptionSome) { + return Some((inner_pat, false)); + } else if is_res_lang_ctor(cx, res, ResultOk) { + return Some((inner_pat, true)); } } None diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index fc655fe2d0b..dd7ded491e7 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -319,7 +319,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R _ => return None, }; if let Some(id) = path_to_local(l) { - if let Some((c, _)) = constant(cx, cx.typeck_results(), r) { + if let Some(c) = constant(cx, cx.typeck_results(), r) { return Some(RangeBounds { val: c, expr: r, @@ -331,7 +331,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R }); } } else if let Some(id) = path_to_local(r) { - if let Some((c, _)) = constant(cx, cx.typeck_results(), l) { + if let Some(c) = constant(cx, cx.typeck_results(), l) { return Some(RangeBounds { val: c, expr: l, @@ -451,8 +451,8 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::Range::hir(expr); let ty = cx.typeck_results().expr_ty(start); if let ty::Int(_) | ty::Uint(_) = ty.kind(); - if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start); - if let Some((end_idx, _)) = constant(cx, cx.typeck_results(), end); + if let Some(start_idx) = constant(cx, cx.typeck_results(), start); + if let Some(end_idx) = constant(cx, cx.typeck_results(), end); if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx); if is_empty_range(limits, ordering); then { diff --git a/src/tools/clippy/clippy_lints/src/ref_patterns.rs b/src/tools/clippy/clippy_lints/src/ref_patterns.rs new file mode 100644 index 00000000000..b1530eed1c1 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/ref_patterns.rs @@ -0,0 +1,44 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_ast::ast::{BindingAnnotation, Pat, PatKind}; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usages of the `ref` keyword. + /// ### Why is this bad? + /// The `ref` keyword can be confusing for people unfamiliar with it, and often + /// it is more concise to use `&` instead. + /// ### Example + /// ```rust + /// let opt = Some(5); + /// if let Some(ref foo) = opt {} + /// ``` + /// Use instead: + /// ```rust + /// let opt = Some(5); + /// if let Some(foo) = &opt {} + /// ``` + #[clippy::version = "1.71.0"] + pub REF_PATTERNS, + restriction, + "use of a ref pattern, e.g. Some(ref value)" +} +declare_lint_pass!(RefPatterns => [REF_PATTERNS]); + +impl EarlyLintPass for RefPatterns { + fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) { + if let PatKind::Ident(BindingAnnotation::REF, _, _) = pat.kind + && !pat.span.from_expansion() + { + span_lint_and_help( + cx, + REF_PATTERNS, + pat.span, + "usage of ref pattern", + None, + "consider using `&` for clarity instead", + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index b8b32df6cc6..ef19c6f4617 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -122,37 +122,39 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescape } fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String> { - constant(cx, cx.typeck_results(), e).and_then(|(c, _)| match c { + constant(cx, cx.typeck_results(), e).and_then(|c| match c { Constant::Str(s) => Some(s), _ => None, }) } fn is_trivial_regex(s: ®ex_syntax::hir::Hir) -> Option<&'static str> { - use regex_syntax::hir::Anchor::{EndText, StartText}; - use regex_syntax::hir::HirKind::{Alternation, Anchor, Concat, Empty, Literal}; + use regex_syntax::hir::HirKind::{Alternation, Concat, Empty, Literal, Look}; + use regex_syntax::hir::Look as HirLook; let is_literal = |e: &[regex_syntax::hir::Hir]| e.iter().all(|e| matches!(*e.kind(), Literal(_))); match *s.kind() { - Empty | Anchor(_) => Some("the regex is unlikely to be useful as it is"), + Empty | Look(_) => Some("the regex is unlikely to be useful as it is"), Literal(_) => Some("consider using `str::contains`"), Alternation(ref exprs) => { - if exprs.iter().all(|e| e.kind().is_empty()) { + if exprs.iter().all(|e| matches!(e.kind(), Empty)) { Some("the regex is unlikely to be useful as it is") } else { None } }, Concat(ref exprs) => match (exprs[0].kind(), exprs[exprs.len() - 1].kind()) { - (&Anchor(StartText), &Anchor(EndText)) if exprs[1..(exprs.len() - 1)].is_empty() => { + (&Look(HirLook::Start), &Look(HirLook::End)) if exprs[1..(exprs.len() - 1)].is_empty() => { Some("consider using `str::is_empty`") }, - (&Anchor(StartText), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => { + (&Look(HirLook::Start), &Look(HirLook::End)) if is_literal(&exprs[1..(exprs.len() - 1)]) => { Some("consider using `==` on `str`s") }, - (&Anchor(StartText), &Literal(_)) if is_literal(&exprs[1..]) => Some("consider using `str::starts_with`"), - (&Literal(_), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => { + (&Look(HirLook::Start), &Literal(_)) if is_literal(&exprs[1..]) => { + Some("consider using `str::starts_with`") + }, + (&Literal(_), &Look(HirLook::End)) if is_literal(&exprs[1..(exprs.len() - 1)]) => { Some("consider using `str::ends_with`") }, _ if is_literal(exprs) => Some("consider using `str::contains`"), @@ -175,10 +177,7 @@ fn check_set<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { } fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { - let mut parser = regex_syntax::ParserBuilder::new() - .unicode(true) - .allow_invalid_utf8(!utf8) - .build(); + let mut parser = regex_syntax::ParserBuilder::new().unicode(true).utf8(!utf8).build(); if let ExprKind::Lit(lit) = expr.kind { if let LitKind::Str(ref r, style) = lit.node { diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index 5e81a01a461..b0db56bb417 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -15,6 +15,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"), ("clippy::identity_conversion", "clippy::useless_conversion"), ("clippy::if_let_some_result", "clippy::match_result_ok"), + ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"), ("clippy::logic_bug", "clippy::overly_complex_bool_expr"), ("clippy::new_without_default_derive", "clippy::new_without_default"), ("clippy::option_and_then_some", "clippy::bind_instead_of_map"), @@ -32,9 +33,13 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::zero_width_space", "clippy::invisible_characters"), ("clippy::clone_double_ref", "suspicious_double_ref_op"), ("clippy::drop_bounds", "drop_bounds"), + ("clippy::drop_copy", "dropping_copy_types"), + ("clippy::drop_ref", "dropping_references"), ("clippy::for_loop_over_option", "for_loops_over_fallibles"), ("clippy::for_loop_over_result", "for_loops_over_fallibles"), ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"), + ("clippy::forget_copy", "forgetting_copy_types"), + ("clippy::forget_ref", "forgetting_references"), ("clippy::into_iter_on_array", "array_into_iter"), ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), ("clippy::invalid_ref", "invalid_value"), diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index 5b588e914fd..483f860a8b5 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -132,7 +132,7 @@ declare_clippy_lint! { /// Probably lots of false positives. If an index comes from a known valid position (e.g. /// obtained via `char_indices` over the same string), it is totally OK. /// - /// # Example + /// ### Example /// ```rust,should_panic /// &"Ölkanne"[1..]; /// ``` diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index b5f11b4acae..4ccda15068b 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -37,12 +37,12 @@ declare_clippy_lint! { #[clippy::version = "1.38.0"] pub TYPE_REPETITION_IN_BOUNDS, nursery, - "types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`" + "types are repeated unnecessarily in trait bounds, use `+` instead of using `T: _, T: _`" } declare_clippy_lint! { /// ### What it does - /// Checks for cases where generics are being used and multiple + /// Checks for cases where generics or trait objects are being used and multiple /// syntax specifications for trait bounds are used simultaneously. /// /// ### Why is this bad? @@ -167,6 +167,61 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { } } } + + fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) { + if_chain! { + if let TyKind::Ref(.., mut_ty) = &ty.kind; + if let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind; + if bounds.len() > 2; + then { + + // Build up a hash of every trait we've seen + // When we see a trait for the first time, add it to unique_traits + // so we can later use it to build a string of all traits exactly once, without duplicates + + let mut seen_def_ids = FxHashSet::default(); + let mut unique_traits = Vec::new(); + + // Iterate the bounds and add them to our seen hash + // If we haven't yet seen it, add it to the fixed traits + for bound in bounds.iter() { + let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; }; + + let new_trait = seen_def_ids.insert(def_id); + + if new_trait { + unique_traits.push(bound); + } + } + + // If the number of unique traits isn't the same as the number of traits in the bounds, + // there must be 1 or more duplicates + if bounds.len() != unique_traits.len() { + let mut bounds_span = bounds[0].span; + + for bound in bounds.iter().skip(1) { + bounds_span = bounds_span.to(bound.span); + } + + let fixed_trait_snippet = unique_traits + .iter() + .filter_map(|b| snippet_opt(cx, b.span)) + .collect::<Vec<_>>() + .join(" + "); + + span_lint_and_sugg( + cx, + TRAIT_DUPLICATION_IN_BOUNDS, + bounds_span, + "this trait bound is already specified in trait declaration", + "try", + fixed_trait_snippet, + Applicability::MaybeIncorrect, + ); + } + } + } + } } impl TraitBounds { diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs index e75d7f6bf1d..4944381da24 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs @@ -31,9 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t match arg.kind { // Catching: // transmute over constants that resolve to `null`. - ExprKind::Path(ref _qpath) - if matches!(constant(cx, cx.typeck_results(), arg), Some((Constant::RawPtr(0), _))) => - { + ExprKind::Path(ref _qpath) if matches!(constant(cx, cx.typeck_results(), arg), Some(Constant::RawPtr(0))) => { lint_expr(cx, expr); true }, diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs index 1e407fc4138..770914e99e1 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant_context, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{is_integer_literal, is_path_diagnostic_item}; use rustc_hir::{Expr, ExprKind}; @@ -16,9 +16,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t } // Catching transmute over constants that resolve to `null`. - let mut const_eval_context = constant_context(cx, cx.typeck_results()); if let ExprKind::Path(ref _qpath) = arg.kind && - let Some(Constant::RawPtr(0)) = const_eval_context.expr(arg) + let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index ddbe6b2c790..28c3fc859e3 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::is_ty_alias; use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; @@ -138,6 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if_chain! { if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); + if !is_ty_alias(qpath); then { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(arg); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index 935ea90d245..3c2bf5abab2 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -308,7 +308,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { bind!(self, vec); kind!("CStr(ref {vec})"); chain!(self, "let [{:?}] = **{vec}", vec.value); - } + }, LitKind::Str(s, _) => { bind!(self, s); kind!("Str({s}, _)"); diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index 5f05d971fce..f6de66bb514 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -174,16 +174,15 @@ macro_rules! define_Conf { } } - #[cfg(feature = "internal")] pub mod metadata { - use crate::utils::internal_lints::metadata_collector::ClippyConfiguration; + use crate::utils::ClippyConfiguration; macro_rules! wrap_option { () => (None); ($x:literal) => (Some($x)); } - pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> { + pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> { vec![ $( { 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 3d0d4a52511..7a1cd3effae 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,7 +8,11 @@ //! a simple mistake) use crate::renamed_lints::RENAMED_LINTS; -use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}; +use crate::utils::{ + collect_configs, + internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}, + ClippyConfiguration, +}; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{match_type, walk_ptrs_ty_depth}; @@ -520,111 +524,6 @@ 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, - #[allow(dead_code)] - 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 to_markdown_paragraph(&self) -> String { - format!( - "### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n", - self.name, - self.doc - .lines() - .map(|line| line.strip_prefix(" ").unwrap_or(line)) - .join("\n"), - self.default, - self.config_type, - self.lints - .iter() - .map(|name| name.to_string().split_whitespace().next().unwrap().to_string()) - .map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) - .join("\n"), - ) - } - - fn to_markdown_table_entry(&self) -> String { - format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default) - } -} - -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 mut documentation = doc_comment.split_off(split_pos); - - // Extract lints - doc_comment.make_ascii_lowercase(); - let lints: Vec<String> = doc_comment - .split_off(DOC_START.len()) - .split(", ") - .map(str::to_string) - .collect(); - - // Format documentation correctly - // split off leading `.` from lint name list and indent for correct formatting - documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n "); - - 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 { writeln!( diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index dc647af264c..d3ea7cafa80 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -4,3 +4,143 @@ pub mod dump_hir; pub mod format_args_collector; #[cfg(feature = "internal")] pub mod internal_lints; +#[cfg(feature = "internal")] +use itertools::Itertools; + +/// Transforms a given `snake_case_string` to a tasty `kebab-case-string` +fn to_kebab(config_name: &str) -> String { + config_name.replace('_', "-") +} + +// ================================================================== +// Configuration +// ================================================================== +#[derive(Debug, Clone, Default)] //~ ERROR no such field +pub struct ClippyConfiguration { + pub name: String, + #[allow(dead_code)] + config_type: &'static str, + pub default: String, + pub lints: Vec<String>, + pub doc: String, + #[allow(dead_code)] + 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, + } + } + + #[cfg(feature = "internal")] + fn to_markdown_paragraph(&self) -> String { + format!( + "### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\n{}\n\n", + self.name, + self.doc + .lines() + .map(|line| line.strip_prefix(" ").unwrap_or(line)) + .join("\n"), + self.default, + self.config_type, + self.lints + .iter() + .map(|name| name.to_string().split_whitespace().next().unwrap().to_string()) + .map(|name| format!("* [{name}](https://rust-lang.github.io/rust-clippy/master/index.html#{name})")) + .join("\n"), + ) + } + + #[cfg(feature = "internal")] + fn to_markdown_table_entry(&self) -> String { + format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default) + } +} + +#[cfg(feature = "internal")] +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 mut documentation = doc_comment.split_off(split_pos); + + // Extract lints + doc_comment.make_ascii_lowercase(); + let lints: Vec<String> = doc_comment + .split_off(DOC_START.len()) + .split(", ") + .map(str::to_string) + .collect(); + + // Format documentation correctly + // split off leading `.` from lint name list and indent for correct formatting + documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n "); + + Some((lints, documentation)) + } else { + None + } + } +} + +// Shamelessly stolen from find_all (https://github.com/nectariner/find_all) +pub trait FindAll: Iterator + Sized { + fn find_all<P>(&mut self, predicate: P) -> Option<Vec<usize>> + where + P: FnMut(&Self::Item) -> bool; +} + +impl<I> FindAll for I +where + I: Iterator, +{ + fn find_all<P>(&mut self, mut predicate: P) -> Option<Vec<usize>> + where + P: FnMut(&Self::Item) -> bool, + { + let mut occurences = Vec::<usize>::default(); + for (index, element) in self.enumerate() { + if predicate(&element) { + occurences.push(index); + } + } + + match occurences.len() { + 0 => None, + _ => Some(occurences), + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs index 297a80e5767..7329e508106 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -84,7 +84,7 @@ impl UselessVec { let mut applicability = Applicability::MachineApplicable; let snippet = match *vec_args { higher::VecArgs::Repeat(elem, len) => { - if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) { + if let Some(Constant::Int(len_constant)) = constant(cx, cx.typeck_results(), len) { #[expect(clippy::cast_possible_truncation)] if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack { return; diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 36f910c983f..a9089fba3c5 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -7,7 +7,7 @@ use rustc_hir::{ def::{DefKind, Res}, Item, ItemKind, PathSegment, UseKind, }; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::kw; @@ -117,6 +117,10 @@ impl_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]); impl LateLintPass<'_> for WildcardImports { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + if cx.sess().is_test_crate() { + return; + } + if is_test_module_or_function(cx.tcx, item) { self.test_modules_deep = self.test_modules_deep.saturating_add(1); } diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index 8075881e3bb..fb772644c0d 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1,18 +1,21 @@ #![allow(clippy::float_cmp)] +use crate::source::{get_source_text, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; use if_chain::if_chain; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; +use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir; use rustc_middle::mir::interpret::Scalar; -use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt}; +use rustc_middle::ty::{List, SubstsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; +use rustc_span::SyntaxContext; use std::cmp::Ordering::{self, Equal}; use std::hash::{Hash, Hasher}; use std::iter; @@ -210,8 +213,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant { match *lit { LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Byte(b) => Constant::Int(u128::from(b)), - LitKind::ByteStr(ref s, _) => Constant::Binary(Lrc::clone(s)), - LitKind::CStr(ref s, _) => Constant::Binary(Lrc::clone(s)), + LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(Lrc::clone(s)), LitKind::Char(c) => Constant::Char(c), LitKind::Int(n, _) => Constant::Int(n), LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty { @@ -228,27 +230,46 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant { } } +/// The source of a constant value. +pub enum ConstantSource { + /// The value is determined solely from the expression. + Local, + /// The value is dependent on a defined constant. + Constant, +} +impl ConstantSource { + pub fn is_local(&self) -> bool { + matches!(self, Self::Local) + } +} + +/// Attempts to evaluate the expression as a constant. pub fn constant<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, -) -> Option<(Constant, bool)> { - let mut cx = ConstEvalLateContext { - lcx, - typeck_results, - param_env: lcx.param_env, - needed_resolution: false, - substs: ty::List::empty(), - }; - cx.expr(e).map(|cst| (cst, cx.needed_resolution)) +) -> Option<Constant> { + ConstEvalLateContext::new(lcx, typeck_results).expr(e) +} + +/// Attempts to evaluate the expression as a constant. +pub fn constant_with_source<'tcx>( + lcx: &LateContext<'tcx>, + typeck_results: &ty::TypeckResults<'tcx>, + e: &Expr<'_>, +) -> Option<(Constant, ConstantSource)> { + let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results); + let res = ctxt.expr(e); + res.map(|x| (x, ctxt.source)) } +/// Attempts to evaluate an expression only if it's value is not dependent on other items. pub fn constant_simple<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, ) -> Option<Constant> { - constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) }) + constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c)) } pub fn constant_full_int<'tcx>( @@ -297,29 +318,25 @@ impl Ord for FullInt { } } -/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`. -pub fn constant_context<'a, 'tcx>( - lcx: &'a LateContext<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, -) -> ConstEvalLateContext<'a, 'tcx> { - ConstEvalLateContext { - lcx, - typeck_results, - param_env: lcx.param_env, - needed_resolution: false, - substs: ty::List::empty(), - } -} - pub struct ConstEvalLateContext<'a, 'tcx> { lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, - needed_resolution: bool, + source: ConstantSource, substs: SubstsRef<'tcx>, } impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { + fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self { + Self { + lcx, + typeck_results, + param_env: lcx.param_env, + source: ConstantSource::Local, + substs: List::empty(), + } + } + /// Simple constant folding: Insert an expression, get a constant or none. pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> { match e.kind { @@ -454,11 +471,9 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None) .ok() .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?; - let result = miri_to_const(self.lcx.tcx, result); - if result.is_some() { - self.needed_resolution = true; - } - result + let result = miri_to_const(self.lcx.tcx, result)?; + self.source = ConstantSource::Constant; + Some(result) }, // FIXME: cover all usable cases. _ => None, @@ -492,8 +507,33 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// A block can only yield a constant if it only has one constant expression. fn block(&mut self, block: &Block<'_>) -> Option<Constant> { - if block.stmts.is_empty() { - block.expr.as_ref().and_then(|b| self.expr(b)) + if block.stmts.is_empty() + && let Some(expr) = block.expr + { + // Try to detect any `cfg`ed statements or empty macro expansions. + let span = block.span.data(); + if span.ctxt == SyntaxContext::root() { + if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) + && let expr_lo = expr_span.lo() + && expr_lo >= span.lo + && let Some(src) = get_source_text(self.lcx, span.lo..expr_lo) + && let Some(src) = src.as_str() + { + use rustc_lexer::TokenKind::{Whitespace, LineComment, BlockComment, Semi, OpenBrace}; + if !tokenize(src) + .map(|t| t.kind) + .filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi)) + .eq([OpenBrace]) + { + self.source = ConstantSource::Constant; + } + } else { + // Unable to access the source. Assume a non-local dependency. + self.source = ConstantSource::Constant; + } + } + + self.expr(expr) } else { None } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 9b7408d5133..a49246a7832 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1,6 +1,7 @@ use crate::consts::constant_simple; use crate::macros::macro_backtrace; -use crate::source::snippet_opt; +use crate::source::{get_source_text, snippet_opt, walk_span_to_context, SpanRange}; +use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; use rustc_hir::def::Res; @@ -13,8 +14,9 @@ use rustc_hir::{ use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; use rustc_middle::ty::TypeckResults; -use rustc_span::{sym, Symbol}; +use rustc_span::{sym, BytePos, ExpnKind, MacroKind, Symbol, SyntaxContext}; use std::hash::{Hash, Hasher}; +use std::ops::Range; /// Callback that is called when two expressions are not equal in the sense of `SpanlessEq`, but /// other conditions would make them equal. @@ -65,6 +67,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub fn inter_expr(&mut self) -> HirEqInterExpr<'_, 'a, 'tcx> { HirEqInterExpr { inner: self, + left_ctxt: SyntaxContext::root(), + right_ctxt: SyntaxContext::root(), locals: HirIdMap::default(), } } @@ -92,6 +96,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub struct HirEqInterExpr<'a, 'b, 'tcx> { inner: &'a mut SpanlessEq<'b, 'tcx>, + left_ctxt: SyntaxContext, + right_ctxt: SyntaxContext, // When binding are declared, the binding ID in the left expression is mapped to the one on the // right. For example, when comparing `{ let x = 1; x + 2 }` and `{ let y = 1; y + 2 }`, @@ -126,52 +132,88 @@ impl HirEqInterExpr<'_, '_, '_> { } /// Checks whether two blocks are the same. + #[expect(clippy::similar_names)] fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool { - match (left.stmts, left.expr, right.stmts, right.expr) { - ([], None, [], None) => { - // For empty blocks, check to see if the tokens are equal. This will catch the case where a macro - // expanded to nothing, or the cfg attribute was used. - let (Some(left), Some(right)) = ( - snippet_opt(self.inner.cx, left.span), - snippet_opt(self.inner.cx, right.span), - ) else { return true }; - let mut left_pos = 0; - let left = tokenize(&left) - .map(|t| { - let end = left_pos + t.len as usize; - let s = &left[left_pos..end]; - left_pos = end; - (t, s) - }) - .filter(|(t, _)| { - !matches!( - t.kind, - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace - ) - }) - .map(|(_, s)| s); - let mut right_pos = 0; - let right = tokenize(&right) - .map(|t| { - let end = right_pos + t.len as usize; - let s = &right[right_pos..end]; - right_pos = end; - (t, s) - }) - .filter(|(t, _)| { - !matches!( - t.kind, - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace - ) - }) - .map(|(_, s)| s); - left.eq(right) - }, - _ => { - over(left.stmts, right.stmts, |l, r| self.eq_stmt(l, r)) - && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) - }, + use TokenKind::{BlockComment, LineComment, Semi, Whitespace}; + if left.stmts.len() != right.stmts.len() { + return false; + } + let lspan = left.span.data(); + let rspan = right.span.data(); + if lspan.ctxt != SyntaxContext::root() && rspan.ctxt != SyntaxContext::root() { + // Don't try to check in between statements inside macros. + return over(left.stmts, right.stmts, |left, right| self.eq_stmt(left, right)) + && both(&left.expr, &right.expr, |left, right| self.eq_expr(left, right)); + } + if lspan.ctxt != rspan.ctxt { + return false; } + + let mut lstart = lspan.lo; + let mut rstart = rspan.lo; + + for (left, right) in left.stmts.iter().zip(right.stmts) { + if !self.eq_stmt(left, right) { + return false; + } + + // Try to detect any `cfg`ed statements or empty macro expansions. + let Some(lstmt_span) = walk_span_to_context(left.span, lspan.ctxt) else { + return false; + }; + let Some(rstmt_span) = walk_span_to_context(right.span, rspan.ctxt) else { + return false; + }; + let lstmt_span = lstmt_span.data(); + let rstmt_span = rstmt_span.data(); + + if lstmt_span.lo < lstart && rstmt_span.lo < rstart { + // Can happen when macros expand to multiple statements, or rearrange statements. + // Nothing in between the statements to check in this case. + continue; + } + if lstmt_span.lo < lstart || rstmt_span.lo < rstart { + // Only one of the blocks had a weird macro. + return false; + } + if !eq_span_tokens(self.inner.cx, lstart..lstmt_span.lo, rstart..rstmt_span.lo, |t| { + !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + }) { + return false; + } + + lstart = lstmt_span.hi; + rstart = rstmt_span.hi; + } + + let (lend, rend) = match (left.expr, right.expr) { + (Some(left), Some(right)) => { + if !self.eq_expr(left, right) { + return false; + } + let Some(lexpr_span) = walk_span_to_context(left.span, lspan.ctxt) else { + return false; + }; + let Some(rexpr_span) = walk_span_to_context(right.span, rspan.ctxt) else { + return false; + }; + (lexpr_span.lo(), rexpr_span.lo()) + }, + (None, None) => (lspan.hi, rspan.hi), + (Some(_), None) | (None, Some(_)) => return false, + }; + + if lend < lstart && rend < rstart { + // Can happen when macros rearrange the input. + // Nothing in between the statements to check in this case. + return true; + } else if lend < lstart || rend < rstart { + // Only one of the blocks had a weird macro + return false; + } + eq_span_tokens(self.inner.cx, lstart..lend, rstart..rend, |t| { + !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + }) } fn should_ignore(&mut self, expr: &Expr<'_>) -> bool { @@ -207,7 +249,7 @@ impl HirEqInterExpr<'_, '_, '_> { #[expect(clippy::similar_names)] pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool { - if !self.inner.allow_side_effects && left.span.ctxt() != right.span.ctxt() { + if !self.check_ctxt(left.span.ctxt(), right.span.ctxt()) { return false; } @@ -440,6 +482,45 @@ impl HirEqInterExpr<'_, '_, '_> { fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool { left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty()) } + + fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool { + if self.left_ctxt == left && self.right_ctxt == right { + return true; + } else if self.left_ctxt == left || self.right_ctxt == right { + // Only one context has changed. This can only happen if the two nodes are written differently. + return false; + } else if left != SyntaxContext::root() { + let mut left_data = left.outer_expn_data(); + let mut right_data = right.outer_expn_data(); + loop { + use TokenKind::{BlockComment, LineComment, Whitespace}; + if left_data.macro_def_id != right_data.macro_def_id + || (matches!(left_data.kind, ExpnKind::Macro(MacroKind::Bang, name) if name == sym::cfg) + && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| { + !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. }) + })) + { + // Either a different chain of macro calls, or different arguments to the `cfg` macro. + return false; + } + let left_ctxt = left_data.call_site.ctxt(); + let right_ctxt = right_data.call_site.ctxt(); + if left_ctxt == SyntaxContext::root() && right_ctxt == SyntaxContext::root() { + break; + } + if left_ctxt == SyntaxContext::root() || right_ctxt == SyntaxContext::root() { + // Different lengths for the expansion stack. This can only happen if nodes are written differently, + // or shouldn't be compared to start with. + return false; + } + left_data = left_ctxt.outer_expn_data(); + right_data = right_ctxt.outer_expn_data(); + } + } + self.left_ctxt = left; + self.right_ctxt = right; + true + } } /// Some simple reductions like `{ return }` => `return` @@ -1038,3 +1119,34 @@ pub fn hash_expr(cx: &LateContext<'_>, e: &Expr<'_>) -> u64 { h.hash_expr(e); h.finish() } + +#[expect(clippy::similar_names)] +fn eq_span_tokens( + cx: &LateContext<'_>, + left: impl SpanRange, + right: impl SpanRange, + pred: impl Fn(TokenKind) -> bool, +) -> bool { + fn f(cx: &LateContext<'_>, left: Range<BytePos>, right: Range<BytePos>, pred: impl Fn(TokenKind) -> bool) -> bool { + if let Some(lsrc) = get_source_text(cx, left) + && let Some(lsrc) = lsrc.as_str() + && let Some(rsrc) = get_source_text(cx, right) + && let Some(rsrc) = rsrc.as_str() + { + let pred = |t: &(_, _)| pred(t.0); + let map = |(_, x)| x; + + let ltok = tokenize_with_text(lsrc) + .filter(pred) + .map(map); + let rtok = tokenize_with_text(rsrc) + .filter(pred) + .map(map); + ltok.eq(rtok) + } else { + // Unable to access the source. Conservatively assume the blocks aren't equal. + false + } + } + f(cx, left.into_range(), right.into_range(), pred) +} diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 964104fc31d..575c29a6b6f 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,5 +1,6 @@ #![feature(array_chunks)] #![feature(box_patterns)] +#![feature(if_let_guard)] #![feature(let_chains)] #![feature(lint_reasons)] #![feature(never_type)] @@ -76,6 +77,7 @@ use std::sync::OnceLock; use std::sync::{Mutex, MutexGuard}; use if_chain::if_chain; +use itertools::Itertools; use rustc_ast::ast::{self, LitKind, RangeLimits}; use rustc_ast::Attribute; use rustc_data_structures::fx::FxHashMap; @@ -282,6 +284,15 @@ pub fn is_wild(pat: &Pat<'_>) -> bool { matches!(pat.kind, PatKind::Wild) } +/// Checks if the given `QPath` belongs to a type alias. +pub fn is_ty_alias(qpath: &QPath<'_>) -> bool { + match *qpath { + QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias, ..)), + QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) }, + _ => false, + } +} + /// Checks if the method call given in `expr` belongs to the given trait. /// This is a deprecated function, consider using [`is_trait_method`]. pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { @@ -1488,7 +1499,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree())) && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty) && let Some(min_const) = miri_to_const(cx.tcx, min_const_kind) - && let Some((start_const, _)) = constant(cx, cx.typeck_results(), start) + && let Some(start_const) = constant(cx, cx.typeck_results(), start) { start_const == min_const } else { @@ -1504,7 +1515,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree())) && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty) && let Some(max_const) = miri_to_const(cx.tcx, max_const_kind) - && let Some((end_const, _)) = constant(cx, cx.typeck_results(), end) + && let Some(end_const) = constant(cx, cx.typeck_results(), end) { end_const == max_const } else { @@ -1536,7 +1547,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool return true; } let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id); - if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) { + if let Some(Constant::Int(v)) = constant(cx, cx.tcx.typeck(enclosing_body), e) { return value == v; } false @@ -2480,6 +2491,17 @@ pub fn walk_to_expr_usage<'tcx, T>( None } +/// Tokenizes the input while keeping the text associated with each token. +pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str)> { + let mut pos = 0; + tokenize(s).map(move |t| { + let end = pos + t.len; + let range = pos as usize..end as usize; + pos = end; + (t.kind, s.get(range).unwrap_or_default()) + }) +} + /// Checks whether a given span has any comment token /// This checks for all types of comment: line "//", block "/**", doc "///" "//!" pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { @@ -2496,23 +2518,11 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { /// Comments are returned wrapped with their relevant delimiters pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String { let snippet = sm.span_to_snippet(span).unwrap_or_default(); - let mut comments_buf: Vec<String> = Vec::new(); - let mut index: usize = 0; - - for token in tokenize(&snippet) { - let token_range = index..(index + token.len as usize); - index += token.len as usize; - match token.kind { - TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => { - if let Some(comment) = snippet.get(token_range) { - comments_buf.push(comment.to_string()); - } - }, - _ => (), - } - } - - comments_buf.join("\n") + let res = tokenize_with_text(&snippet) + .filter(|(t, _)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) + .map(|(_, s)| s) + .join("\n"); + res } pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 62fa37660fa..0f60290644a 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -2,14 +2,64 @@ #![allow(clippy::module_name_repetitions)] +use rustc_data_structures::sync::Lrc; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_session::Session; -use rustc_span::hygiene; use rustc_span::source_map::{original_sp, SourceMap}; +use rustc_span::{hygiene, SourceFile}; use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP}; use std::borrow::Cow; +use std::ops::Range; + +/// A type which can be converted to the range portion of a `Span`. +pub trait SpanRange { + fn into_range(self) -> Range<BytePos>; +} +impl SpanRange for Span { + fn into_range(self) -> Range<BytePos> { + let data = self.data(); + data.lo..data.hi + } +} +impl SpanRange for SpanData { + fn into_range(self) -> Range<BytePos> { + self.lo..self.hi + } +} +impl SpanRange for Range<BytePos> { + fn into_range(self) -> Range<BytePos> { + self + } +} + +pub struct SourceFileRange { + pub sf: Lrc<SourceFile>, + pub range: Range<usize>, +} +impl SourceFileRange { + /// Attempts to get the text from the source file. This can fail if the source text isn't + /// loaded. + pub fn as_str(&self) -> Option<&str> { + self.sf.src.as_ref().and_then(|x| x.get(self.range.clone())) + } +} + +/// Gets the source file, and range in the file, of the given span. Returns `None` if the span +/// extends through multiple files, or is malformed. +pub fn get_source_text(cx: &impl LintContext, sp: impl SpanRange) -> Option<SourceFileRange> { + fn f(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> { + let start = sm.lookup_byte_offset(sp.start); + let end = sm.lookup_byte_offset(sp.end); + if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { + return None; + } + let range = start.pos.to_usize()..end.pos.to_usize(); + Some(SourceFileRange { sf: start.sf, range }) + } + f(cx.sess().source_map(), sp.into_range()) +} /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. pub fn expr_block<T: LintContext>( diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 60b8a5ac071..bc7fb711ed8 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-05-05" +channel = "nightly-2023-05-20" components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"] diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs index acb98d7ba98..99ce7028390 100644 --- a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs +++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs @@ -3,6 +3,7 @@ //@normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs" //@normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints" //@normalize-stderr-test: "'rustc'" -> "'<unnamed>'" +//@normalize-stderr-test: "running on .*" -> "running on <target>" //@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" #![deny(clippy::internal)] diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr index b4619e980f3..0fc385cd693 100644 --- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr @@ -1,12 +1,14 @@ thread '<unnamed>' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -error: internal compiler error: unexpected panic - -note: the compiler unexpectedly panicked. this is a bug. +error: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new +note: rustc 1.71.0-nightly (521f4dae1 2023-05-19) running on <target> + +note: compiler flags: -C prefer-dynamic -Z ui-testing + note: Clippy version: foo thread panicked while panicking. aborting. diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs index ab408bdf261..f95af1017bc 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs @@ -458,4 +458,12 @@ pub fn issue_10583(a: u16) -> u16 { 10 / a } +pub fn issue_10767() { + let n = &1.0; + n + n; + 3.1_f32 + &1.2_f32; + &3.4_f32 + 1.5_f32; + &3.5_f32 + &1.3_f32; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed index 165e4bc8272..75526461792 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed @@ -1,7 +1,11 @@ //@run-rustfix +//@aux-build: proc_macros.rs #![allow(dead_code, unused_variables)] +extern crate proc_macros; +use proc_macros::with_span; + fn main() {} mod should_lint { @@ -47,6 +51,17 @@ mod should_not_lint2 { } } +with_span!( + span + + fn just_returning(x: &u32) -> &u32 { + x + } + + fn dont_lint_proc_macro() { + let a = &mut &*just_returning(&12); + } +); // this mod explains why we should not lint `& &* (&T)` mod false_negative { fn foo() { diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.rs b/src/tools/clippy/tests/ui/borrow_deref_ref.rs index 66c8d69bef9..e319d365f7e 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.rs +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.rs @@ -1,7 +1,11 @@ //@run-rustfix +//@aux-build: proc_macros.rs #![allow(dead_code, unused_variables)] +extern crate proc_macros; +use proc_macros::with_span; + fn main() {} mod should_lint { @@ -47,6 +51,17 @@ mod should_not_lint2 { } } +with_span!( + span + + fn just_returning(x: &u32) -> &u32 { + x + } + + fn dont_lint_proc_macro() { + let a = &mut &*just_returning(&12); + } +); // this mod explains why we should not lint `& &* (&T)` mod false_negative { fn foo() { diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr index d72de37c69f..1e47cda6796 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr @@ -1,5 +1,5 @@ error: deref on an immutable reference - --> $DIR/borrow_deref_ref.rs:10:17 + --> $DIR/borrow_deref_ref.rs:14:17 | LL | let b = &*a; | ^^^ help: if you would like to reborrow, try removing `&*`: `a` @@ -7,13 +7,13 @@ LL | let b = &*a; = note: `-D clippy::borrow-deref-ref` implied by `-D warnings` error: deref on an immutable reference - --> $DIR/borrow_deref_ref.rs:12:22 + --> $DIR/borrow_deref_ref.rs:16:22 | LL | let b = &mut &*bar(&12); | ^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `bar(&12)` error: deref on an immutable reference - --> $DIR/borrow_deref_ref.rs:55:23 + --> $DIR/borrow_deref_ref.rs:70:23 | LL | let addr_y = &&*x as *const _ as usize; // assert ok | ^^^ help: if you would like to reborrow, try removing `&*`: `x` diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed index e6331290420..840902b5323 100644 --- a/src/tools/clippy/tests/ui/box_default.fixed +++ b/src/tools/clippy/tests/ui/box_default.fixed @@ -35,6 +35,13 @@ fn main() { let _more = ret_ty_fn(); call_ty_fn(Box::default()); issue_10381(); + + // `Box::<Option<_>>::default()` would be valid here, but not `Box::default()` or + // `Box::<Option<[closure@...]>::default()` + // + // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563 + let mut unnameable = Box::new(Option::default()); + let _ = unnameable.insert(|| {}); } fn ret_ty_fn() -> Box<bool> { diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs index 34a05a29c5a..3618486a473 100644 --- a/src/tools/clippy/tests/ui/box_default.rs +++ b/src/tools/clippy/tests/ui/box_default.rs @@ -35,6 +35,13 @@ fn main() { let _more = ret_ty_fn(); call_ty_fn(Box::new(u8::default())); issue_10381(); + + // `Box::<Option<_>>::default()` would be valid here, but not `Box::default()` or + // `Box::<Option<[closure@...]>::default()` + // + // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563 + let mut unnameable = Box::new(Option::default()); + let _ = unnameable.insert(|| {}); } fn ret_ty_fn() -> Box<bool> { diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr index c9834863601..13dfc5ae48a 100644 --- a/src/tools/clippy/tests/ui/box_default.stderr +++ b/src/tools/clippy/tests/ui/box_default.stderr @@ -73,25 +73,25 @@ LL | call_ty_fn(Box::new(u8::default())); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:41:5 + --> $DIR/box_default.rs:48:5 | LL | Box::new(bool::default()) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:58:28 + --> $DIR/box_default.rs:65:28 | LL | let _: Box<dyn Read> = Box::new(ImplementsDefault::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:67:17 + --> $DIR/box_default.rs:74:17 | LL | let _ = Box::new(WeirdPathed::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:79:18 + --> $DIR/box_default.rs:86:18 | LL | Some(Box::new(Foo::default())) | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Foo>::default()` diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed index d2aba2ac59b..c6514a55934 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.fixed +++ b/src/tools/clippy/tests/ui/collapsible_if.fixed @@ -1,5 +1,10 @@ //@run-rustfix -#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] +#![allow( + clippy::assertions_on_constants, + clippy::equatable_if_let, + clippy::nonminimal_bool, + clippy::eq_op +)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs index e0bef7f9c97..2c85b68df63 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.rs +++ b/src/tools/clippy/tests/ui/collapsible_if.rs @@ -1,5 +1,10 @@ //@run-rustfix -#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] +#![allow( + clippy::assertions_on_constants, + clippy::equatable_if_let, + clippy::nonminimal_bool, + clippy::eq_op +)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/src/tools/clippy/tests/ui/collapsible_if.stderr b/src/tools/clippy/tests/ui/collapsible_if.stderr index 6327444df21..c687bae1acc 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.stderr +++ b/src/tools/clippy/tests/ui/collapsible_if.stderr @@ -1,5 +1,5 @@ error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:9:5 + --> $DIR/collapsible_if.rs:14:5 | LL | / if x == "hello" { LL | | if y == "world" { @@ -17,7 +17,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:15:5 + --> $DIR/collapsible_if.rs:20:5 | LL | / if x == "hello" || x == "world" { LL | | if y == "world" || y == "hello" { @@ -34,7 +34,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:21:5 + --> $DIR/collapsible_if.rs:26:5 | LL | / if x == "hello" && x == "world" { LL | | if y == "world" || y == "hello" { @@ -51,7 +51,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:27:5 + --> $DIR/collapsible_if.rs:32:5 | LL | / if x == "hello" || x == "world" { LL | | if y == "world" && y == "hello" { @@ -68,7 +68,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:33:5 + --> $DIR/collapsible_if.rs:38:5 | LL | / if x == "hello" && x == "world" { LL | | if y == "world" && y == "hello" { @@ -85,7 +85,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:39:5 + --> $DIR/collapsible_if.rs:44:5 | LL | / if 42 == 1337 { LL | | if 'a' != 'A' { @@ -102,7 +102,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:95:5 + --> $DIR/collapsible_if.rs:100:5 | LL | / if x == "hello" { LL | | if y == "world" { // Collapsible @@ -119,7 +119,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:154:5 + --> $DIR/collapsible_if.rs:159:5 | LL | / if matches!(true, true) { LL | | if matches!(true, true) {} @@ -127,7 +127,7 @@ LL | | } | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}` error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:159:5 + --> $DIR/collapsible_if.rs:164:5 | LL | / if matches!(true, true) && truth() { LL | | if matches!(true, true) {} diff --git a/src/tools/clippy/tests/ui/dbg_macro.rs b/src/tools/clippy/tests/ui/dbg_macro.rs index 8701e3cd29f..10788d40481 100644 --- a/src/tools/clippy/tests/ui/dbg_macro.rs +++ b/src/tools/clippy/tests/ui/dbg_macro.rs @@ -4,6 +4,7 @@ fn foo(n: u32) -> u32 { if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } } +fn bar(_: ()) {} fn factorial(n: u32) -> u32 { if dbg!(n <= 1) { @@ -21,6 +22,32 @@ fn main() { dbg!(1, 2, 3, 4, 5); } +fn issue9914() { + macro_rules! foo { + ($x:expr) => { + $x; + }; + } + macro_rules! foo2 { + ($x:expr) => { + $x; + }; + } + macro_rules! expand_to_dbg { + () => { + dbg!(); + }; + } + + dbg!(); + #[allow(clippy::let_unit_value)] + let _ = dbg!(); + bar(dbg!()); + foo!(dbg!()); + foo2!(foo!(dbg!())); + expand_to_dbg!(); +} + mod issue7274 { trait Thing<'b> { fn foo(&self); diff --git a/src/tools/clippy/tests/ui/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro.stderr index ddb5f1342e9..530e7663317 100644 --- a/src/tools/clippy/tests/ui/dbg_macro.stderr +++ b/src/tools/clippy/tests/ui/dbg_macro.stderr @@ -11,7 +11,7 @@ LL | if let Some(n) = n.checked_sub(4) { n } else { n } | ~~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:9:8 + --> $DIR/dbg_macro.rs:10:8 | LL | if dbg!(n <= 1) { | ^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | if n <= 1 { | ~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:10:9 + --> $DIR/dbg_macro.rs:11:9 | LL | dbg!(1) | ^^^^^^^ @@ -33,7 +33,7 @@ LL | 1 | error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:12:9 + --> $DIR/dbg_macro.rs:13:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | n * factorial(n - 1) | error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:17:5 + --> $DIR/dbg_macro.rs:18:5 | LL | dbg!(42); | ^^^^^^^^ @@ -55,7 +55,7 @@ LL | 42; | ~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:18:5 + --> $DIR/dbg_macro.rs:19:5 | LL | dbg!(dbg!(dbg!(42))); | ^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | dbg!(dbg!(42)); | ~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:19:14 + --> $DIR/dbg_macro.rs:20:14 | LL | foo(3) + dbg!(factorial(4)); | ^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | foo(3) + factorial(4); | ~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:20:5 + --> $DIR/dbg_macro.rs:21:5 | LL | dbg!(1, 2, dbg!(3, 4)); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | (1, 2, dbg!(3, 4)); | ~~~~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:21:5 + --> $DIR/dbg_macro.rs:22:5 | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,63 @@ LL | (1, 2, 3, 4, 5); | ~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:41:9 + --> $DIR/dbg_macro.rs:42:5 + | +LL | dbg!(); + | ^^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL - dbg!(); +LL + + | + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:44:13 + | +LL | let _ = dbg!(); + | ^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | let _ = (); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:45:9 + | +LL | bar(dbg!()); + | ^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | bar(()); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:46:10 + | +LL | foo!(dbg!()); + | ^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | foo!(()); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:47:16 + | +LL | foo2!(foo!(dbg!())); + | ^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | foo2!(foo!(())); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:68:9 | LL | dbg!(2); | ^^^^^^^ @@ -110,7 +166,7 @@ LL | 2; | ~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:47:5 + --> $DIR/dbg_macro.rs:74:5 | LL | dbg!(1); | ^^^^^^^ @@ -121,7 +177,7 @@ LL | 1; | ~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:52:5 + --> $DIR/dbg_macro.rs:79:5 | LL | dbg!(1); | ^^^^^^^ @@ -132,7 +188,7 @@ LL | 1; | ~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:58:9 + --> $DIR/dbg_macro.rs:85:9 | LL | dbg!(1); | ^^^^^^^ @@ -142,5 +198,5 @@ help: remove the invocation before committing it to a version control system LL | 1; | ~ -error: aborting due to 13 previous errors +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed index 4c2d1ea48e1..e1012f38bba 100644 --- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed @@ -105,6 +105,7 @@ fn main() { // should lint let _ = PhantomData::<usize>; let _: PhantomData<i32> = PhantomData; + let _: PhantomData<i32> = std::marker::PhantomData; let _ = UnitStruct; // should not lint @@ -116,4 +117,21 @@ fn main() { let _ = EmptyStruct::default(); let _ = FakeDefault::default(); let _ = <FakeDefault as Default>::default(); + + macro_rules! in_macro { + ($i:ident) => {{ + let _ = UnitStruct::default(); + let _ = $i::default(); + }}; + } + + in_macro!(UnitStruct); + + macro_rules! struct_from_macro { + () => { + UnitStruct + }; + } + + let _ = <struct_from_macro!()>::default(); } diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs index 850793dd5de..c7b4313dbf0 100644 --- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs @@ -105,6 +105,7 @@ fn main() { // should lint let _ = PhantomData::<usize>::default(); let _: PhantomData<i32> = PhantomData::default(); + let _: PhantomData<i32> = std::marker::PhantomData::default(); let _ = UnitStruct::default(); // should not lint @@ -116,4 +117,21 @@ fn main() { let _ = EmptyStruct::default(); let _ = FakeDefault::default(); let _ = <FakeDefault as Default>::default(); + + macro_rules! in_macro { + ($i:ident) => {{ + let _ = UnitStruct::default(); + let _ = $i::default(); + }}; + } + + in_macro!(UnitStruct); + + macro_rules! struct_from_macro { + () => { + UnitStruct + }; + } + + let _ = <struct_from_macro!()>::default(); } diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr index 4058943d087..61a32fb10e5 100644 --- a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr @@ -25,10 +25,16 @@ LL | let _: PhantomData<i32> = PhantomData::default(); | ^^^^^^^^^^^ help: remove this call to `default` error: use of `default` to create a unit struct - --> $DIR/default_constructed_unit_structs.rs:108:23 + --> $DIR/default_constructed_unit_structs.rs:108:55 + | +LL | let _: PhantomData<i32> = std::marker::PhantomData::default(); + | ^^^^^^^^^^^ help: remove this call to `default` + +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_structs.rs:109:23 | LL | let _ = UnitStruct::default(); | ^^^^^^^^^^^ help: remove this call to `default` -error: aborting due to 5 previous errors +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.stderr b/src/tools/clippy/tests/ui/diverging_sub_expression.stderr index 9c91d935716..51a3b0d972e 100644 --- a/src/tools/clippy/tests/ui/diverging_sub_expression.stderr +++ b/src/tools/clippy/tests/ui/diverging_sub_expression.stderr @@ -31,18 +31,10 @@ LL | 3 => true || diverge(), | ^^^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:36:30 - | -LL | _ => true || panic!("boo"), - | ^^^^^^^^^^^^^ - | - = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: sub-expression diverges --> $DIR/diverging_sub_expression.rs:38:26 | LL | _ => true || break, | ^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors diff --git a/src/tools/clippy/tests/ui/drop_forget_copy.rs b/src/tools/clippy/tests/ui/drop_forget_copy.rs deleted file mode 100644 index a7276dd59f4..00000000000 --- a/src/tools/clippy/tests/ui/drop_forget_copy.rs +++ /dev/null @@ -1,86 +0,0 @@ -#![warn(clippy::drop_copy, clippy::forget_copy)] -#![allow(clippy::toplevel_ref_arg, clippy::drop_ref, clippy::forget_ref, unused_mut)] - -use std::mem::{drop, forget}; -use std::vec::Vec; - -#[derive(Copy, Clone)] -struct SomeStruct; - -struct AnotherStruct { - x: u8, - y: u8, - z: Vec<u8>, -} - -impl Clone for AnotherStruct { - fn clone(&self) -> AnotherStruct { - AnotherStruct { - x: self.x, - y: self.y, - z: self.z.clone(), - } - } -} - -fn main() { - let s1 = SomeStruct {}; - let s2 = s1; - let s3 = &s1; - let mut s4 = s1; - let ref s5 = s1; - - drop(s1); - drop(s2); - drop(s3); - drop(s4); - drop(s5); - - forget(s1); - forget(s2); - forget(s3); - forget(s4); - forget(s5); - - let a1 = AnotherStruct { - x: 255, - y: 0, - z: vec![1, 2, 3], - }; - let a2 = &a1; - let mut a3 = a1.clone(); - let ref a4 = a1; - let a5 = a1.clone(); - - drop(a2); - drop(a3); - drop(a4); - drop(a5); - - forget(a2); - let a3 = &a1; - forget(a3); - forget(a4); - let a5 = a1.clone(); - forget(a5); -} - -#[allow(unused)] -#[allow(clippy::unit_cmp)] -fn issue9482(x: u8) { - fn println_and<T>(t: T) -> T { - println!("foo"); - t - } - - match x { - 0 => drop(println_and(12)), // Don't lint (copy type), we only care about side-effects - 1 => drop(println_and(String::new())), // Don't lint (no copy type), we only care about side-effects - 2 => { - drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block - }, - 3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm` - 4 => drop(2), // Lint, not a fn/method call - _ => (), - } -} diff --git a/src/tools/clippy/tests/ui/drop_forget_copy.stderr b/src/tools/clippy/tests/ui/drop_forget_copy.stderr deleted file mode 100644 index 90bef1c3c43..00000000000 --- a/src/tools/clippy/tests/ui/drop_forget_copy.stderr +++ /dev/null @@ -1,112 +0,0 @@ -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:33:5 - | -LL | drop(s1); - | ^^^^^^^^ - | -note: argument has type `SomeStruct` - --> $DIR/drop_forget_copy.rs:33:10 - | -LL | drop(s1); - | ^^ - = note: `-D clippy::drop-copy` implied by `-D warnings` - -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:34:5 - | -LL | drop(s2); - | ^^^^^^^^ - | -note: argument has type `SomeStruct` - --> $DIR/drop_forget_copy.rs:34:10 - | -LL | drop(s2); - | ^^ - -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:36:5 - | -LL | drop(s4); - | ^^^^^^^^ - | -note: argument has type `SomeStruct` - --> $DIR/drop_forget_copy.rs:36:10 - | -LL | drop(s4); - | ^^ - -error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:39:5 - | -LL | forget(s1); - | ^^^^^^^^^^ - | -note: argument has type `SomeStruct` - --> $DIR/drop_forget_copy.rs:39:12 - | -LL | forget(s1); - | ^^ - = note: `-D clippy::forget-copy` implied by `-D warnings` - -error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:40:5 - | -LL | forget(s2); - | ^^^^^^^^^^ - | -note: argument has type `SomeStruct` - --> $DIR/drop_forget_copy.rs:40:12 - | -LL | forget(s2); - | ^^ - -error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:42:5 - | -LL | forget(s4); - | ^^^^^^^^^^ - | -note: argument has type `SomeStruct` - --> $DIR/drop_forget_copy.rs:42:12 - | -LL | forget(s4); - | ^^ - -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:80:13 - | -LL | drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `i32` - --> $DIR/drop_forget_copy.rs:80:18 - | -LL | drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block - | ^^^^^^^^^^^^^^^ - -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:82:14 - | -LL | 3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm` - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `i32` - --> $DIR/drop_forget_copy.rs:82:19 - | -LL | 3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm` - | ^^^^^^^^^^^^^^^ - -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:83:14 - | -LL | 4 => drop(2), // Lint, not a fn/method call - | ^^^^^^^ - | -note: argument has type `i32` - --> $DIR/drop_forget_copy.rs:83:19 - | -LL | 4 => drop(2), // Lint, not a fn/method call - | ^ - -error: aborting due to 9 previous errors - diff --git a/src/tools/clippy/tests/ui/drop_ref.stderr b/src/tools/clippy/tests/ui/drop_ref.stderr deleted file mode 100644 index 293b9f6de83..00000000000 --- a/src/tools/clippy/tests/ui/drop_ref.stderr +++ /dev/null @@ -1,147 +0,0 @@ -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:11:5 - | -LL | drop(&SomeStruct); - | ^^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:11:10 - | -LL | drop(&SomeStruct); - | ^^^^^^^^^^^ - = note: `-D clippy::drop-ref` implied by `-D warnings` - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:14:5 - | -LL | drop(&owned1); - | ^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:14:10 - | -LL | drop(&owned1); - | ^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:15:5 - | -LL | drop(&&owned1); - | ^^^^^^^^^^^^^^ - | -note: argument has type `&&SomeStruct` - --> $DIR/drop_ref.rs:15:10 - | -LL | drop(&&owned1); - | ^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:16:5 - | -LL | drop(&mut owned1); - | ^^^^^^^^^^^^^^^^^ - | -note: argument has type `&mut SomeStruct` - --> $DIR/drop_ref.rs:16:10 - | -LL | drop(&mut owned1); - | ^^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:20:5 - | -LL | drop(reference1); - | ^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:20:10 - | -LL | drop(reference1); - | ^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:23:5 - | -LL | drop(reference2); - | ^^^^^^^^^^^^^^^^ - | -note: argument has type `&mut SomeStruct` - --> $DIR/drop_ref.rs:23:10 - | -LL | drop(reference2); - | ^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:26:5 - | -LL | drop(reference3); - | ^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:26:10 - | -LL | drop(reference3); - | ^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:31:5 - | -LL | drop(&val); - | ^^^^^^^^^^ - | -note: argument has type `&T` - --> $DIR/drop_ref.rs:31:10 - | -LL | drop(&val); - | ^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:39:5 - | -LL | std::mem::drop(&SomeStruct); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:39:20 - | -LL | std::mem::drop(&SomeStruct); - | ^^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:91:13 - | -LL | drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block - | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&i32` - --> $DIR/drop_ref.rs:91:18 - | -LL | drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block - | ^^^^^^^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:93:14 - | -LL | 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm` - | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&i32` - --> $DIR/drop_ref.rs:93:19 - | -LL | 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm` - | ^^^^^^^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:94:14 - | -LL | 4 => drop(&2), // Lint, not a fn/method call - | ^^^^^^^^ - | -note: argument has type `&i32` - --> $DIR/drop_ref.rs:94:19 - | -LL | 4 => drop(&2), // Lint, not a fn/method call - | ^^ - -error: aborting due to 12 previous errors - diff --git a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs new file mode 100644 index 00000000000..e843770f578 --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs @@ -0,0 +1,132 @@ +//@aux-build:proc_macro_attr.rs +#![warn(clippy::empty_line_after_doc_comments)] +#![allow(clippy::assertions_on_constants)] +#![feature(custom_inner_attributes)] +#![rustfmt::skip] + +#[macro_use] +extern crate proc_macro_attr; + +mod some_mod { + //! This doc comment should *NOT* produce a warning + + mod some_inner_mod { + fn some_noop() {} + } +} + +/// This should produce a warning + +fn with_doc_and_newline() { assert!(true)} + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +/// some comment +fn with_one_newline_and_comment() { assert!(true) } + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/// some comment +fn with_no_newline_and_comment() { assert!(true) } + + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +fn with_one_newline() { assert!(true) } + +// This should *NOT* produce a warning +#[crate_type = "lib"] + + +fn with_two_newlines() { assert!(true) } + + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +enum Baz { + One, + Two +} + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +struct Foo { + one: isize, + two: isize +} + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +mod foo { +} + +/// This doc comment should produce a warning + +/** This is also a doc comment and should produce a warning + */ + +// This should *NOT* produce a warning +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[allow(missing_docs)] +fn three_attributes() { assert!(true) } + +// This should *NOT* produce a warning +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +// This should *NOT* produce a warning +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4 +} + +// This should *NOT* produce a warning because the empty line is inside a block comment +#[crate_type = "lib"] +/* + +*/ +pub struct S; + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/* test */ +pub struct T; + +// This should *NOT* produce a warning +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec<u8> { + let _i = ""; + + + + vec![] + } +} + +#[derive(Clone, Copy)] +#[dummy(string = "first line + +second line +")] +pub struct Args; + +fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr new file mode 100644 index 00000000000..2ca1b51679e --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr @@ -0,0 +1,36 @@ +error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? + --> $DIR/empty_line_after_doc_comments.rs:18:1 + | +LL | / /// This should produce a warning +LL | | +LL | | fn with_doc_and_newline() { assert!(true)} + | |_ + | + = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings` + +error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? + --> $DIR/empty_line_after_doc_comments.rs:68:1 + | +LL | / /// This doc comment should produce a warning +LL | | +LL | | /** This is also a doc comment and should produce a warning +LL | | */ +... | +LL | | #[allow(missing_docs)] +LL | | fn three_attributes() { assert!(true) } + | |_ + +error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? + --> $DIR/empty_line_after_doc_comments.rs:70:1 + | +LL | / /** This is also a doc comment and should produce a warning +LL | | */ +LL | | +LL | | // This should *NOT* produce a warning +... | +LL | | #[allow(missing_docs)] +LL | | fn three_attributes() { assert!(true) } + | |_ + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/float_arithmetic.rs b/src/tools/clippy/tests/ui/float_arithmetic.rs index 60fa7569eb9..a928c35e8bc 100644 --- a/src/tools/clippy/tests/ui/float_arithmetic.rs +++ b/src/tools/clippy/tests/ui/float_arithmetic.rs @@ -1,4 +1,4 @@ -#![warn(clippy::integer_arithmetic, clippy::float_arithmetic)] +#![warn(clippy::arithmetic_side_effects, clippy::float_arithmetic)] #![allow( unused, clippy::shadow_reuse, diff --git a/src/tools/clippy/tests/ui/forget_ref.rs b/src/tools/clippy/tests/ui/forget_ref.rs deleted file mode 100644 index 031b415f56f..00000000000 --- a/src/tools/clippy/tests/ui/forget_ref.rs +++ /dev/null @@ -1,50 +0,0 @@ -#![warn(clippy::forget_ref)] -#![allow(clippy::toplevel_ref_arg)] -#![allow(clippy::unnecessary_wraps, clippy::forget_non_drop)] -#![allow(clippy::borrow_deref_ref)] - -use std::mem::forget; - -struct SomeStruct; - -fn main() { - forget(&SomeStruct); - - let mut owned = SomeStruct; - forget(&owned); - forget(&&owned); - forget(&mut owned); - forget(owned); //OK - - let reference1 = &SomeStruct; - forget(&*reference1); - - let reference2 = &mut SomeStruct; - forget(reference2); - - let ref reference3 = SomeStruct; - forget(reference3); -} - -#[allow(dead_code)] -fn test_generic_fn_forget<T>(val: T) { - forget(&val); - forget(val); //OK -} - -#[allow(dead_code)] -fn test_similarly_named_function() { - fn forget<T>(_val: T) {} - forget(&SomeStruct); //OK; call to unrelated function which happens to have the same name - std::mem::forget(&SomeStruct); -} - -#[derive(Copy, Clone)] -pub struct Error; -fn produce_half_owl_error() -> Result<(), Error> { - Ok(()) -} - -fn produce_half_owl_ok() -> Result<bool, ()> { - Ok(true) -} diff --git a/src/tools/clippy/tests/ui/forget_ref.stderr b/src/tools/clippy/tests/ui/forget_ref.stderr deleted file mode 100644 index 011cdefc665..00000000000 --- a/src/tools/clippy/tests/ui/forget_ref.stderr +++ /dev/null @@ -1,111 +0,0 @@ -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:11:5 - | -LL | forget(&SomeStruct); - | ^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:11:12 - | -LL | forget(&SomeStruct); - | ^^^^^^^^^^^ - = note: `-D clippy::forget-ref` implied by `-D warnings` - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:14:5 - | -LL | forget(&owned); - | ^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:14:12 - | -LL | forget(&owned); - | ^^^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:15:5 - | -LL | forget(&&owned); - | ^^^^^^^^^^^^^^^ - | -note: argument has type `&&SomeStruct` - --> $DIR/forget_ref.rs:15:12 - | -LL | forget(&&owned); - | ^^^^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:16:5 - | -LL | forget(&mut owned); - | ^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&mut SomeStruct` - --> $DIR/forget_ref.rs:16:12 - | -LL | forget(&mut owned); - | ^^^^^^^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:20:5 - | -LL | forget(&*reference1); - | ^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:20:12 - | -LL | forget(&*reference1); - | ^^^^^^^^^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:23:5 - | -LL | forget(reference2); - | ^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&mut SomeStruct` - --> $DIR/forget_ref.rs:23:12 - | -LL | forget(reference2); - | ^^^^^^^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:26:5 - | -LL | forget(reference3); - | ^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:26:12 - | -LL | forget(reference3); - | ^^^^^^^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:31:5 - | -LL | forget(&val); - | ^^^^^^^^^^^^ - | -note: argument has type `&T` - --> $DIR/forget_ref.rs:31:12 - | -LL | forget(&val); - | ^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:39:5 - | -LL | std::mem::forget(&SomeStruct); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:39:22 - | -LL | std::mem::forget(&SomeStruct); - | ^^^^^^^^^^^ - -error: aborting due to 9 previous errors - diff --git a/src/tools/clippy/tests/ui/integer_arithmetic.rs b/src/tools/clippy/tests/ui/integer_arithmetic.rs deleted file mode 100644 index ab9b6094c2c..00000000000 --- a/src/tools/clippy/tests/ui/integer_arithmetic.rs +++ /dev/null @@ -1,109 +0,0 @@ -//@aux-build:proc_macro_derive.rs - -#![warn(clippy::integer_arithmetic, clippy::float_arithmetic)] -#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::op_ref)] - -extern crate proc_macro_derive; - -#[derive(proc_macro_derive::ShadowDerive)] -pub struct Nothing; - -#[rustfmt::skip] -fn main() { - let mut i = 1i32; - let mut var1 = 13i32; - let mut var2 = -1i32; - 1 + i; - i * 2; - 1 % - i / 2; // no error, this is part of the expression in the preceding line - i - 2 + 2 - i; - -i; - i >> 1; - i << 1; - - // no error, overflows are checked by `overflowing_literals` - -1; - -(-1); - - i & 1; // no wrapping - i | 1; - i ^ 1; - - i += 1; - i -= 1; - i *= 2; - i /= 2; - i /= 0; - i /= -1; - i /= var1; - i /= var2; - i %= 2; - i %= 0; - i %= -1; - i %= var1; - i %= var2; - i <<= 3; - i >>= 2; - - // no errors - i |= 1; - i &= 1; - i ^= i; - - // No errors for the following items because they are constant expressions - enum Foo { - Bar = -2, - } - struct Baz([i32; 1 + 1]); - union Qux { - field: [i32; 1 + 1], - } - type Alias = [i32; 1 + 1]; - - const FOO: i32 = -2; - static BAR: i32 = -2; - - let _: [i32; 1 + 1] = [0, 0]; - - let _: [i32; 1 + 1] = { - let a: [i32; 1 + 1] = [0, 0]; - a - }; - - trait Trait { - const ASSOC: i32 = 1 + 1; - } - - impl Trait for Foo { - const ASSOC: i32 = { - let _: [i32; 1 + 1]; - fn foo() {} - 1 + 1 - }; - } -} - -// warn on references as well! (#5328) -pub fn int_arith_ref() { - 3 + &1; - &3 + 1; - &3 + &1; -} - -pub fn foo(x: &i32) -> i32 { - let a = 5; - a + x -} - -pub fn bar(x: &i32, y: &i32) -> i32 { - x + y -} - -pub fn baz(x: i32, y: &i32) -> i32 { - x + y -} - -pub fn qux(x: i32, y: i32) -> i32 { - (&x + &y) -} diff --git a/src/tools/clippy/tests/ui/integer_arithmetic.stderr b/src/tools/clippy/tests/ui/integer_arithmetic.stderr deleted file mode 100644 index add3b6b90fa..00000000000 --- a/src/tools/clippy/tests/ui/integer_arithmetic.stderr +++ /dev/null @@ -1,169 +0,0 @@ -error: this operation will panic at runtime - --> $DIR/integer_arithmetic.rs:37:5 - | -LL | i /= 0; - | ^^^^^^ attempt to divide `_` by zero - | - = note: `#[deny(unconditional_panic)]` on by default - -error: this operation will panic at runtime - --> $DIR/integer_arithmetic.rs:42:5 - | -LL | i %= 0; - | ^^^^^^ attempt to calculate the remainder of `_` with a divisor of zero - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:16:5 - | -LL | 1 + i; - | ^^^^^ - | - = note: `-D clippy::integer-arithmetic` implied by `-D warnings` - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:17:5 - | -LL | i * 2; - | ^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:18:5 - | -LL | / 1 % -LL | | i / 2; // no error, this is part of the expression in the preceding line - | |_____^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:20:5 - | -LL | i - 2 + 2 - i; - | ^^^^^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:21:5 - | -LL | -i; - | ^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:22:5 - | -LL | i >> 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:23:5 - | -LL | i << 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:33:5 - | -LL | i += 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:34:5 - | -LL | i -= 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:35:5 - | -LL | i *= 2; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:38:11 - | -LL | i /= -1; - | ^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:39:5 - | -LL | i /= var1; - | ^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:40:5 - | -LL | i /= var2; - | ^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:43:11 - | -LL | i %= -1; - | ^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:44:5 - | -LL | i %= var1; - | ^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:45:5 - | -LL | i %= var2; - | ^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:46:5 - | -LL | i <<= 3; - | ^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:47:5 - | -LL | i >>= 2; - | ^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:89:5 - | -LL | 3 + &1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:90:5 - | -LL | &3 + 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:91:5 - | -LL | &3 + &1; - | ^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:96:5 - | -LL | a + x - | ^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:100:5 - | -LL | x + y - | ^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:104:5 - | -LL | x + y - | ^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:108:5 - | -LL | (&x + &y) - | ^^^^^^^^^ - -error: aborting due to 27 previous errors - diff --git a/src/tools/clippy/tests/ui/issue-111399.rs b/src/tools/clippy/tests/ui/issue-111399.rs new file mode 100644 index 00000000000..b65e6c7261a --- /dev/null +++ b/src/tools/clippy/tests/ui/issue-111399.rs @@ -0,0 +1,13 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +// Check that rustc doesn't crash on the trait bound `Self::Ty: std::marker::Freeze`. + +pub struct Struct; + +impl Struct { + pub type Ty = usize; + pub const CT: Self::Ty = 42; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.rs b/src/tools/clippy/tests/ui/let_underscore_untyped.rs index 8486137d3a6..2c313ff35d5 100644 --- a/src/tools/clippy/tests/ui/let_underscore_untyped.rs +++ b/src/tools/clippy/tests/ui/let_underscore_untyped.rs @@ -1,6 +1,12 @@ +//@aux-build: proc_macros.rs + #![allow(unused)] #![warn(clippy::let_underscore_untyped)] +extern crate proc_macros; +use proc_macros::with_span; + +use clippy_utils::is_from_proc_macro; use std::future::Future; use std::{boxed::Box, fmt::Display}; @@ -32,6 +38,14 @@ fn g() -> impl Fn() { || {} } +with_span!( + span + + fn dont_lint_proc_macro() { + let _ = a(); + } +); + fn main() { let _ = a(); let _ = b(1); @@ -40,6 +54,7 @@ fn main() { let _ = e(); let _ = f(); let _ = g(); + let closure = || {}; _ = a(); _ = b(1); diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr index 6844cb998f7..bbf2508af10 100644 --- a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr @@ -1,60 +1,60 @@ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:36:5 + --> $DIR/let_underscore_untyped.rs:50:5 | LL | let _ = a(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:36:10 + --> $DIR/let_underscore_untyped.rs:50:10 | LL | let _ = a(); | ^ = note: `-D clippy::let-underscore-untyped` implied by `-D warnings` error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:37:5 + --> $DIR/let_underscore_untyped.rs:51:5 | LL | let _ = b(1); | ^^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:37:10 + --> $DIR/let_underscore_untyped.rs:51:10 | LL | let _ = b(1); | ^ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:39:5 + --> $DIR/let_underscore_untyped.rs:53:5 | LL | let _ = d(&1); | ^^^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:39:10 + --> $DIR/let_underscore_untyped.rs:53:10 | LL | let _ = d(&1); | ^ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:40:5 + --> $DIR/let_underscore_untyped.rs:54:5 | LL | let _ = e(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:40:10 + --> $DIR/let_underscore_untyped.rs:54:10 | LL | let _ = e(); | ^ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:41:5 + --> $DIR/let_underscore_untyped.rs:55:5 | LL | let _ = f(); | ^^^^^^^^^^^^ | help: consider adding a type annotation - --> $DIR/let_underscore_untyped.rs:41:10 + --> $DIR/let_underscore_untyped.rs:55:10 | LL | let _ = f(); | ^ diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs index d175597a44a..3996d775f55 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.rs +++ b/src/tools/clippy/tests/ui/manual_let_else.rs @@ -8,6 +8,12 @@ )] #![warn(clippy::manual_let_else)] +enum Variant { + A(usize, usize), + B(usize), + C, +} + fn g() -> Option<()> { None } @@ -135,6 +141,15 @@ fn fire() { }; } create_binding_if_some!(w, g()); + + fn e() -> Variant { + Variant::A(0, 0) + } + + // Should not be renamed + let v = if let Variant::A(a, 0) = e() { a } else { return }; + // Should be renamed + let v = if let Variant::B(b) = e() { b } else { return }; } fn not_fire() { diff --git a/src/tools/clippy/tests/ui/manual_let_else.stderr b/src/tools/clippy/tests/ui/manual_let_else.stderr index 52aac6bc673..f6f56f7b00e 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else.stderr @@ -1,13 +1,13 @@ error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:18:5 + --> $DIR/manual_let_else.rs:24:5 | LL | let v = if let Some(v_some) = g() { v_some } else { return }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { return };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` | = note: `-D clippy::manual-let-else` implied by `-D warnings` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:19:5 + --> $DIR/manual_let_else.rs:25:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -18,13 +18,13 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + return; LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:25:5 + --> $DIR/manual_let_else.rs:31:5 | LL | / let v = if let Some(v) = g() { LL | | // Blocks around the identity should have no impact @@ -45,25 +45,25 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:38:9 + --> $DIR/manual_let_else.rs:44:9 | LL | let v = if let Some(v_some) = g() { v_some } else { continue }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { continue };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:39:9 + --> $DIR/manual_let_else.rs:45:9 | LL | let v = if let Some(v_some) = g() { v_some } else { break }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { break };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:43:5 + --> $DIR/manual_let_else.rs:49:5 | LL | let v = if let Some(v_some) = g() { v_some } else { panic!() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { panic!() };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:46:5 + --> $DIR/manual_let_else.rs:52:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -74,13 +74,13 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + std::process::abort() LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:53:5 + --> $DIR/manual_let_else.rs:59:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -91,13 +91,13 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + if true { return } else { panic!() } LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:60:5 + --> $DIR/manual_let_else.rs:66:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -109,14 +109,14 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + if true {} LL + panic!(); LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:70:5 + --> $DIR/manual_let_else.rs:76:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -129,7 +129,7 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + match () { LL + _ if panic!() => {}, LL + _ => panic!(), @@ -138,13 +138,13 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:80:5 + --> $DIR/manual_let_else.rs:86:5 | LL | let v = if let Some(v_some) = g() { v_some } else { if panic!() {} }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { if panic!() {} };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { if panic!() {} };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:83:5 + --> $DIR/manual_let_else.rs:89:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -157,7 +157,7 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + match panic!() { LL + _ => {}, LL + } @@ -165,7 +165,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:92:5 + --> $DIR/manual_let_else.rs:98:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -178,7 +178,7 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { if true { +LL ~ let Some(v) = g() else { if true { LL + return; LL + } else { LL + panic!("diverge"); @@ -186,7 +186,7 @@ LL + } }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:101:5 + --> $DIR/manual_let_else.rs:107:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -199,7 +199,7 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + match (g(), g()) { LL + (Some(_), None) => return, LL + (None, Some(_)) => { @@ -215,7 +215,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:118:5 + --> $DIR/manual_let_else.rs:124:5 | LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) { LL | | v_some @@ -226,13 +226,13 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g().map(|v| (v, 42)) else { +LL ~ let Some((v, w)) = g().map(|v| (v, 42)) else { LL + return; LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:125:5 + --> $DIR/manual_let_else.rs:131:5 | LL | / let v = if let (Some(v_some), w_some) = (g(), 0) { LL | | (w_some, v_some) @@ -249,10 +249,10 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:134:13 + --> $DIR/manual_let_else.rs:140:13 | LL | let $n = if let Some(v) = $e { v } else { return }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };` ... LL | create_binding_if_some!(w, g()); | ------------------------------- in this macro invocation @@ -260,13 +260,25 @@ LL | create_binding_if_some!(w, g()); = note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info) error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:247:5 + --> $DIR/manual_let_else.rs:150:5 + | +LL | let v = if let Variant::A(a, 0) = e() { a } else { return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(a, 0) = e() else { return };` + +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else.rs:152:5 + | +LL | let v = if let Variant::B(b) = e() { b } else { return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(v) = e() else { return };` + +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else.rs:262:5 | LL | / let _ = match ff { LL | | Some(value) => value, LL | | _ => macro_call!(), LL | | }; - | |______^ help: consider writing: `let Some(value) = ff else { macro_call!() };` + | |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };` -error: aborting due to 18 previous errors +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.stderr b/src/tools/clippy/tests/ui/manual_let_else_match.stderr index 7abaa0b85d2..bacc14dc967 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_match.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else_match.stderr @@ -5,7 +5,7 @@ LL | / let v = match g() { LL | | Some(v_some) => v_some, LL | | None => return, LL | | }; - | |______^ help: consider writing: `let Some(v_some) = g() else { return };` + | |______^ help: consider writing: `let Some(v) = g() else { return };` | = note: `-D clippy::manual-let-else` implied by `-D warnings` @@ -16,7 +16,7 @@ LL | / let v = match g() { LL | | Some(v_some) => v_some, LL | | _ => return, LL | | }; - | |______^ help: consider writing: `let Some(v_some) = g() else { return };` + | |______^ help: consider writing: `let Some(v) = g() else { return };` error: this could be rewritten as `let...else` --> $DIR/manual_let_else_match.rs:44:9 diff --git a/src/tools/clippy/tests/ui/manual_next_back.fixed b/src/tools/clippy/tests/ui/manual_next_back.fixed new file mode 100644 index 00000000000..e8a47063ad6 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_next_back.fixed @@ -0,0 +1,36 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_next_back)] + +struct FakeIter(std::ops::Range<i32>); + +impl FakeIter { + fn rev(self) -> Self { + self + } + + fn next(&self) {} +} + +impl DoubleEndedIterator for FakeIter { + fn next_back(&mut self) -> Option<Self::Item> { + self.0.next_back() + } +} + +impl Iterator for FakeIter { + type Item = i32; + fn next(&mut self) -> Option<Self::Item> { + self.0.next() + } +} + +fn main() { + // should not lint + FakeIter(0..10).rev().next(); + + // should lint + let _ = (0..10).next_back().unwrap(); + let _ = "something".bytes().next_back(); +} diff --git a/src/tools/clippy/tests/ui/manual_next_back.rs b/src/tools/clippy/tests/ui/manual_next_back.rs new file mode 100644 index 00000000000..9ec89242241 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_next_back.rs @@ -0,0 +1,36 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_next_back)] + +struct FakeIter(std::ops::Range<i32>); + +impl FakeIter { + fn rev(self) -> Self { + self + } + + fn next(&self) {} +} + +impl DoubleEndedIterator for FakeIter { + fn next_back(&mut self) -> Option<Self::Item> { + self.0.next_back() + } +} + +impl Iterator for FakeIter { + type Item = i32; + fn next(&mut self) -> Option<Self::Item> { + self.0.next() + } +} + +fn main() { + // should not lint + FakeIter(0..10).rev().next(); + + // should lint + let _ = (0..10).rev().next().unwrap(); + let _ = "something".bytes().rev().next(); +} diff --git a/src/tools/clippy/tests/ui/manual_next_back.stderr b/src/tools/clippy/tests/ui/manual_next_back.stderr new file mode 100644 index 00000000000..94ccaa9e4cc --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_next_back.stderr @@ -0,0 +1,16 @@ +error: manual backwards iteration + --> $DIR/manual_next_back.rs:34:20 + | +LL | let _ = (0..10).rev().next().unwrap(); + | ^^^^^^^^^^^^^ help: use: `.next_back()` + | + = note: `-D clippy::manual-next-back` implied by `-D warnings` + +error: manual backwards iteration + --> $DIR/manual_next_back.rs:35:32 + | +LL | let _ = "something".bytes().rev().next(); + | ^^^^^^^^^^^^^ help: use: `.next_back()` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed index 7215660da67..60f59066173 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed @@ -15,7 +15,7 @@ fn main() { let _y = matches!(x, Some(0)); // Lint - let _w = matches!(x, Some(_)); + let _w = x.is_some(); // Turn into is_none let _z = x.is_none(); diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr index 46f67ef4900..b72fe10b748 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr @@ -10,7 +10,7 @@ LL | | }; | = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` -error: match expression looks like `matches!` macro +error: redundant pattern matching, consider using `is_some()` --> $DIR/match_expr_like_matches_macro.rs:21:14 | LL | let _w = match x { @@ -18,7 +18,9 @@ LL | let _w = match x { LL | | Some(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `matches!(x, Some(_))` + | |_____^ help: try this: `x.is_some()` + | + = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_none()` --> $DIR/match_expr_like_matches_macro.rs:27:14 @@ -29,8 +31,6 @@ LL | | Some(_) => false, LL | | None => true, LL | | }; | |_____^ help: try this: `x.is_none()` - | - = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:33:15 diff --git a/src/tools/clippy/tests/ui/match_same_arms.rs b/src/tools/clippy/tests/ui/match_same_arms.rs index 0b9342c9c42..3914b45464c 100644 --- a/src/tools/clippy/tests/ui/match_same_arms.rs +++ b/src/tools/clippy/tests/ui/match_same_arms.rs @@ -53,4 +53,84 @@ mod issue4244 { } } -fn main() {} +macro_rules! m { + (foo) => {}; + (bar) => {}; +} +macro_rules! foo { + () => { + 1 + }; +} +macro_rules! bar { + () => { + 1 + }; +} + +fn main() { + let x = 0; + let _ = match 0 { + 0 => { + m!(foo); + x + }, + 1 => { + m!(bar); + x + }, + _ => 1, + }; + + let _ = match 0 { + 0 => { + m!(foo); + 0 + }, + 1 => { + m!(bar); + 0 + }, + _ => 1, + }; + + let _ = match 0 { + 0 => { + let mut x = 0; + #[cfg(not_enabled)] + { + x = 5; + } + #[cfg(not(not_enabled))] + { + x = 6; + } + x + }, + 1 => { + let mut x = 0; + #[cfg(also_not_enabled)] + { + x = 5; + } + #[cfg(not(also_not_enabled))] + { + x = 6; + } + x + }, + _ => 0, + }; + + let _ = match 0 { + 0 => foo!(), + 1 => bar!(), + _ => 1, + }; + + let _ = match 0 { + 0 => cfg!(not_enabled), + 1 => cfg!(also_not_enabled), + _ => false, + }; +} diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs index 82b2c433d99..60b2975be04 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.rs +++ b/src/tools/clippy/tests/ui/match_same_arms2.rs @@ -239,4 +239,10 @@ fn main() { 3 => core::convert::identity::<u32>(todo!()), _ => 5, }; + + let _ = match 0 { + 0 => cfg!(not_enable), + 1 => cfg!(not_enable), + _ => false, + }; } diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr index 06cd4300054..8fb461bd286 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr @@ -192,5 +192,20 @@ note: other arm here LL | Some(Bar { x: 0, y: 5, .. }) => 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: this match arm has an identical body to another arm + --> $DIR/match_same_arms2.rs:245:9 + | +LL | 1 => cfg!(not_enable), + | -^^^^^^^^^^^^^^^^^^^^ + | | + | help: try merging the arm patterns: `1 | 0` + | + = help: or try changing either arm body +note: other arm here + --> $DIR/match_same_arms2.rs:244:9 + | +LL | 0 => cfg!(not_enable), + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/mem_forget.rs b/src/tools/clippy/tests/ui/mem_forget.rs index e5b35c098a2..edb9d87d032 100644 --- a/src/tools/clippy/tests/ui/mem_forget.rs +++ b/src/tools/clippy/tests/ui/mem_forget.rs @@ -5,7 +5,7 @@ use std::mem as memstuff; use std::mem::forget as forgetSomething; #[warn(clippy::mem_forget)] -#[allow(clippy::forget_copy)] +#[allow(forgetting_copy_types)] fn main() { let five: i32 = 5; forgetSomething(five); diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs index 73ef35c8c36..4ef6f0ca92f 100644 --- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs +++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs @@ -2,7 +2,7 @@ #![allow(unused)] #![allow(deref_nullptr)] #![allow(clippy::unnecessary_operation)] -#![allow(clippy::drop_copy)] +#![allow(dropping_copy_types)] #![warn(clippy::multiple_unsafe_ops_per_block)] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed index f860852e7b7..bf1911881c8 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed @@ -63,6 +63,13 @@ fn main() { needless_bool2(x); needless_bool3(x); needless_bool_condition(); + + if a == b { + true + } else { + // Do not lint as this comment might be important + false + }; } fn bool_ret3(x: bool) -> bool { diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.rs b/src/tools/clippy/tests/ui/needless_bool/fixable.rs index 6680dab5b6d..a6c465d4fbd 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.rs +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.rs @@ -99,6 +99,13 @@ fn main() { needless_bool2(x); needless_bool3(x); needless_bool_condition(); + + if a == b { + true + } else { + // Do not lint as this comment might be important + false + }; } fn bool_ret3(x: bool) -> bool { diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr index d2c48376f76..fa906374fb3 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr @@ -91,7 +91,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a < b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:105:5 + --> $DIR/fixable.rs:112:5 | LL | / if x { LL | | return true; @@ -101,7 +101,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:113:5 + --> $DIR/fixable.rs:120:5 | LL | / if x { LL | | return false; @@ -111,7 +111,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:121:5 + --> $DIR/fixable.rs:128:5 | LL | / if x && y { LL | | return true; @@ -121,7 +121,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:129:5 + --> $DIR/fixable.rs:136:5 | LL | / if x && y { LL | | return false; @@ -131,7 +131,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !(x && y)` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:137:8 + --> $DIR/fixable.rs:144:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -139,25 +139,25 @@ LL | if x == true {}; = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:141:8 + --> $DIR/fixable.rs:148:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:151:8 + --> $DIR/fixable.rs:158:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:152:8 + --> $DIR/fixable.rs:159:8 | LL | if x == false {}; | ^^^^^^^^^^ help: try simplifying it as shown: `!x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:161:12 + --> $DIR/fixable.rs:168:12 | LL | } else if returns_bool() { | ____________^ @@ -168,7 +168,7 @@ LL | | }; | |_____^ help: you can reduce it to: `{ !returns_bool() }` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:174:5 + --> $DIR/fixable.rs:181:5 | LL | / if unsafe { no(4) } & 1 != 0 { LL | | true @@ -178,13 +178,13 @@ LL | | }; | |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:179:30 + --> $DIR/fixable.rs:186:30 | LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:182:9 + --> $DIR/fixable.rs:189:9 | LL | if unsafe { no(4) } & 1 != 0 { true } else { false } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)` diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed index 024c22de225..b7e80af5015 100644 --- a/src/tools/clippy/tests/ui/needless_collect.fixed +++ b/src/tools/clippy/tests/ui/needless_collect.fixed @@ -62,4 +62,16 @@ fn main() { let _ = sample.iter().next().is_none(); let _ = sample.iter().any(|x| x == &0); + + #[allow(clippy::double_parens)] + { + Vec::<u8>::new().extend((0..10)); + foo((0..10)); + bar((0..10).collect::<Vec<_>>(), (0..10)); + baz((0..10), (), ('a'..='z')) + } } + +fn foo(_: impl IntoIterator<Item = usize>) {} +fn bar<I: IntoIterator<Item = usize>>(_: Vec<usize>, _: I) {} +fn baz<I: IntoIterator<Item = usize>>(_: I, _: (), _: impl IntoIterator<Item = char>) {} diff --git a/src/tools/clippy/tests/ui/needless_collect.rs b/src/tools/clippy/tests/ui/needless_collect.rs index 7ed7babec30..680b6fa5b55 100644 --- a/src/tools/clippy/tests/ui/needless_collect.rs +++ b/src/tools/clippy/tests/ui/needless_collect.rs @@ -62,4 +62,16 @@ fn main() { let _ = sample.iter().collect::<VecWrapper<_>>().is_empty(); let _ = sample.iter().collect::<VecWrapper<_>>().contains(&&0); + + #[allow(clippy::double_parens)] + { + Vec::<u8>::new().extend((0..10).collect::<Vec<_>>()); + foo((0..10).collect::<Vec<_>>()); + bar((0..10).collect::<Vec<_>>(), (0..10).collect::<Vec<_>>()); + baz((0..10), (), ('a'..='z').collect::<Vec<_>>()) + } } + +fn foo(_: impl IntoIterator<Item = usize>) {} +fn bar<I: IntoIterator<Item = usize>>(_: Vec<usize>, _: I) {} +fn baz<I: IntoIterator<Item = usize>>(_: I, _: (), _: impl IntoIterator<Item = char>) {} diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr index 584d2a1d835..ad22a7b057e 100644 --- a/src/tools/clippy/tests/ui/needless_collect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect.stderr @@ -90,5 +90,29 @@ error: avoid using `collect()` when not needed LL | let _ = sample.iter().collect::<VecWrapper<_>>().contains(&&0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &0)` -error: aborting due to 15 previous errors +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:68:40 + | +LL | Vec::<u8>::new().extend((0..10).collect::<Vec<_>>()); + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:69:20 + | +LL | foo((0..10).collect::<Vec<_>>()); + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:70:49 + | +LL | bar((0..10).collect::<Vec<_>>(), (0..10).collect::<Vec<_>>()); + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:71:37 + | +LL | baz((0..10), (), ('a'..='z').collect::<Vec<_>>()) + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index ee4e5007dc5..d49ae5d8636 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -231,8 +231,9 @@ fn needless_return_macro() -> String { } fn issue_9361() -> i32 { - #[allow(clippy::integer_arithmetic)] - return 1 + 2; + let n = 1; + #[allow(clippy::arithmetic_side_effects)] + return n + n; } fn issue8336(x: i32) -> bool { diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index cd999db4f40..36763826174 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -239,8 +239,9 @@ fn needless_return_macro() -> String { } fn issue_9361() -> i32 { - #[allow(clippy::integer_arithmetic)] - return 1 + 2; + let n = 1; + #[allow(clippy::arithmetic_side_effects)] + return n + n; } fn issue8336(x: i32) -> bool { diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index 87d0cd3e14c..05f6038cd25 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -328,7 +328,7 @@ LL | return format!("Hello {}", "world!"); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:249:9 + --> $DIR/needless_return.rs:250:9 | LL | return true; | ^^^^^^^^^^^ @@ -336,7 +336,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:251:9 + --> $DIR/needless_return.rs:252:9 | LL | return false; | ^^^^^^^^^^^^ @@ -344,7 +344,7 @@ LL | return false; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:258:13 + --> $DIR/needless_return.rs:259:13 | LL | return 10; | ^^^^^^^^^ @@ -352,7 +352,7 @@ LL | return 10; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:261:13 + --> $DIR/needless_return.rs:262:13 | LL | return 100; | ^^^^^^^^^^ @@ -360,7 +360,7 @@ LL | return 100; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:269:9 + --> $DIR/needless_return.rs:270:9 | LL | return 0; | ^^^^^^^^ @@ -368,7 +368,7 @@ LL | return 0; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:276:13 + --> $DIR/needless_return.rs:277:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | return *(x as *const isize); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:278:13 + --> $DIR/needless_return.rs:279:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -384,7 +384,7 @@ LL | return !*(x as *const isize); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:285:20 + --> $DIR/needless_return.rs:286:20 | LL | let _ = 42; | ____________________^ @@ -395,7 +395,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:292:20 + --> $DIR/needless_return.rs:293:20 | LL | let _ = 42; return; | ^^^^^^^ @@ -403,7 +403,7 @@ LL | let _ = 42; return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:304:9 + --> $DIR/needless_return.rs:305:9 | LL | return Ok(format!("ok!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -411,7 +411,7 @@ LL | return Ok(format!("ok!")); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:306:9 + --> $DIR/needless_return.rs:307:9 | LL | return Err(format!("err!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -419,7 +419,7 @@ LL | return Err(format!("err!")); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:312:9 + --> $DIR/needless_return.rs:313:9 | LL | return if true { 1 } else { 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | return if true { 1 } else { 2 }; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:316:9 + --> $DIR/needless_return.rs:317:9 | LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.fixed b/src/tools/clippy/tests/ui/non_minimal_cfg.fixed new file mode 100644 index 00000000000..430caafb33e --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.fixed @@ -0,0 +1,17 @@ +//@run-rustfix + +#![allow(unused)] + +#[cfg(windows)] +fn hermit() {} + +#[cfg(windows)] +fn wasi() {} + +#[cfg(all(unix, not(windows)))] +fn the_end() {} + +#[cfg(any())] +fn any() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.rs b/src/tools/clippy/tests/ui/non_minimal_cfg.rs new file mode 100644 index 00000000000..a38ce1c21d6 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.rs @@ -0,0 +1,17 @@ +//@run-rustfix + +#![allow(unused)] + +#[cfg(all(windows))] +fn hermit() {} + +#[cfg(any(windows))] +fn wasi() {} + +#[cfg(all(any(unix), all(not(windows))))] +fn the_end() {} + +#[cfg(any())] +fn any() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.stderr b/src/tools/clippy/tests/ui/non_minimal_cfg.stderr new file mode 100644 index 00000000000..cdfd728aa61 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.stderr @@ -0,0 +1,28 @@ +error: unneeded sub `cfg` when there is only one condition + --> $DIR/non_minimal_cfg.rs:5:7 + | +LL | #[cfg(all(windows))] + | ^^^^^^^^^^^^ help: try: `windows` + | + = note: `-D clippy::non-minimal-cfg` implied by `-D warnings` + +error: unneeded sub `cfg` when there is only one condition + --> $DIR/non_minimal_cfg.rs:8:7 + | +LL | #[cfg(any(windows))] + | ^^^^^^^^^^^^ help: try: `windows` + +error: unneeded sub `cfg` when there is only one condition + --> $DIR/non_minimal_cfg.rs:11:11 + | +LL | #[cfg(all(any(unix), all(not(windows))))] + | ^^^^^^^^^ help: try: `unix` + +error: unneeded sub `cfg` when there is only one condition + --> $DIR/non_minimal_cfg.rs:11:22 + | +LL | #[cfg(all(any(unix), all(not(windows))))] + | ^^^^^^^^^^^^^^^^^ help: try: `not(windows)` + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg2.rs b/src/tools/clippy/tests/ui/non_minimal_cfg2.rs new file mode 100644 index 00000000000..a4c6abce387 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg2.rs @@ -0,0 +1,6 @@ +#![allow(unused)] + +#[cfg(all())] +fn all() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr b/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr new file mode 100644 index 00000000000..2a9a36fbcef --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr @@ -0,0 +1,10 @@ +error: unneeded sub `cfg` when there is no condition + --> $DIR/non_minimal_cfg2.rs:3:7 + | +LL | #[cfg(all())] + | ^^^^^ + | + = note: `-D clippy::non-minimal-cfg` implied by `-D warnings` + +error: aborting due to previous error + 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 57f341e0276..2b8ce5477cc 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.fixed +++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed @@ -92,6 +92,15 @@ fn pattern_to_vec(pattern: &str) -> Vec<String> { .collect::<Vec<_>>() } +// #10335 +fn test_result_impure_else(variable: Result<u32, &str>) { + variable.map_or_else(|_| { + println!("Err"); + }, |binding| { + println!("Ok {binding}"); + }) +} + enum DummyEnum { One(u8), Two, @@ -113,6 +122,7 @@ fn main() { unop_bad(&None, None); let _ = longer_body(None); test_map_or_else(None); + test_result_impure_else(Ok(42)); let _ = negative_tests(None); let _ = impure_else(None); diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs index 19f9f704517..cfbec8cb27d 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.rs +++ b/src/tools/clippy/tests/ui/option_if_let_else.rs @@ -115,6 +115,15 @@ fn pattern_to_vec(pattern: &str) -> Vec<String> { .collect::<Vec<_>>() } +// #10335 +fn test_result_impure_else(variable: Result<u32, &str>) { + if let Ok(binding) = variable { + println!("Ok {binding}"); + } else { + println!("Err"); + } +} + enum DummyEnum { One(u8), Two, @@ -136,6 +145,7 @@ fn main() { unop_bad(&None, None); let _ = longer_body(None); test_map_or_else(None); + test_result_impure_else(Ok(42)); let _ = negative_tests(None); let _ = impure_else(None); 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 f5e4affb672..91d52fc79b8 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.stderr +++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr @@ -152,14 +152,33 @@ LL | | vec![s.to_string()] LL | | } | |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])` +error: use Option::map_or_else instead of an if let/else + --> $DIR/option_if_let_else.rs:120:5 + | +LL | / if let Ok(binding) = variable { +LL | | println!("Ok {binding}"); +LL | | } else { +LL | | println!("Err"); +LL | | } + | |_____^ + | +help: try + | +LL ~ variable.map_or_else(|_| { +LL + println!("Err"); +LL + }, |binding| { +LL + println!("Ok {binding}"); +LL + }) + | + error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:133:13 + --> $DIR/option_if_let_else.rs:142:13 | LL | let _ = if let Some(x) = optional { x + 2 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:142:13 + --> $DIR/option_if_let_else.rs:152:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -181,13 +200,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:170:13 + --> $DIR/option_if_let_else.rs:180:13 | LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:174:13 + --> $DIR/option_if_let_else.rs:184:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -207,7 +226,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:213:13 + --> $DIR/option_if_let_else.rs:223:13 | LL | let _ = match s { | _____________^ @@ -217,7 +236,7 @@ LL | | }; | |_____^ help: try: `s.map_or(1, |string| string.len())` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:217:13 + --> $DIR/option_if_let_else.rs:227:13 | LL | let _ = match Some(10) { | _____________^ @@ -227,7 +246,7 @@ LL | | }; | |_____^ help: try: `Some(10).map_or(5, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:223:13 + --> $DIR/option_if_let_else.rs:233:13 | LL | let _ = match res { | _____________^ @@ -237,7 +256,7 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:227:13 + --> $DIR/option_if_let_else.rs:237:13 | LL | let _ = match res { | _____________^ @@ -247,10 +266,10 @@ LL | | }; | |_____^ help: try: `res.map_or(1, |a| a + 1)` error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:231:13 + --> $DIR/option_if_let_else.rs:241:13 | LL | let _ = if let Ok(a) = res { a + 1 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)` -error: aborting due to 20 previous errors +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.fixed b/src/tools/clippy/tests/ui/partialeq_to_none.fixed index 81a716bd276..2df87a26d6d 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.fixed +++ b/src/tools/clippy/tests/ui/partialeq_to_none.fixed @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::partialeq_to_none)] +#![allow(clippy::eq_op)] struct Foobar; diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.rs b/src/tools/clippy/tests/ui/partialeq_to_none.rs index f454715fa30..df6233b9afd 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.rs +++ b/src/tools/clippy/tests/ui/partialeq_to_none.rs @@ -1,5 +1,6 @@ //@run-rustfix #![warn(clippy::partialeq_to_none)] +#![allow(clippy::eq_op)] struct Foobar; diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.stderr b/src/tools/clippy/tests/ui/partialeq_to_none.stderr index d06ab7aee55..4f84862a22b 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.stderr +++ b/src/tools/clippy/tests/ui/partialeq_to_none.stderr @@ -1,5 +1,5 @@ error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:14:8 + --> $DIR/partialeq_to_none.rs:15:8 | LL | if f != None { "yay" } else { "nay" } | ^^^^^^^^^ help: use `Option::is_some()` instead: `f.is_some()` @@ -7,55 +7,55 @@ LL | if f != None { "yay" } else { "nay" } = note: `-D clippy::partialeq-to-none` implied by `-D warnings` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:44:13 + --> $DIR/partialeq_to_none.rs:45:13 | LL | let _ = x == None; | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:45:13 + --> $DIR/partialeq_to_none.rs:46:13 | LL | let _ = x != None; | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:46:13 + --> $DIR/partialeq_to_none.rs:47:13 | LL | let _ = None == x; | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:47:13 + --> $DIR/partialeq_to_none.rs:48:13 | LL | let _ = None != x; | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:49:8 + --> $DIR/partialeq_to_none.rs:50:8 | LL | if foobar() == None {} | ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:51:8 + --> $DIR/partialeq_to_none.rs:52:8 | LL | if bar().ok() != None {} | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:53:13 + --> $DIR/partialeq_to_none.rs:54:13 | LL | let _ = Some(1 + 2) != None; | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:55:13 + --> $DIR/partialeq_to_none.rs:56:13 | LL | let _ = { Some(0) } == None; | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:57:13 + --> $DIR/partialeq_to_none.rs:58:13 | LL | let _ = { | _____________^ @@ -77,31 +77,31 @@ LL ~ }.is_some(); | error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:67:13 + --> $DIR/partialeq_to_none.rs:68:13 | LL | let _ = optref() == &&None; | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:68:13 + --> $DIR/partialeq_to_none.rs:69:13 | LL | let _ = &&None != optref(); | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:69:13 + --> $DIR/partialeq_to_none.rs:70:13 | LL | let _ = **optref() == None; | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:70:13 + --> $DIR/partialeq_to_none.rs:71:13 | LL | let _ = &None != *optref(); | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:73:13 + --> $DIR/partialeq_to_none.rs:74:13 | LL | let _ = None != *x; | ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()` diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed index d62f7d26a35..accdf1da9dd 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed @@ -46,6 +46,7 @@ fn main() { let _ = if opt.is_some() { true } else { false }; issue6067(); + issue10726(); let _ = if gen_opt().is_some() { 1 @@ -88,3 +89,21 @@ fn issue7921() { if (&None::<()>).is_none() {} if (&None::<()>).is_none() {} } + +fn issue10726() { + let x = Some(42); + + x.is_some(); + + x.is_none(); + + x.is_none(); + + x.is_some(); + + // Don't lint + match x { + Some(21) => true, + _ => false, + }; +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs index d6429426573..ec684bdf71c 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs @@ -55,6 +55,7 @@ fn main() { let _ = if let Some(_) = opt { true } else { false }; issue6067(); + issue10726(); let _ = if let Some(_) = gen_opt() { 1 @@ -103,3 +104,33 @@ fn issue7921() { if let None = *(&None::<()>) {} if let None = *&None::<()> {} } + +fn issue10726() { + let x = Some(42); + + match x { + Some(_) => true, + _ => false, + }; + + match x { + None => true, + _ => false, + }; + + match x { + Some(_) => false, + _ => true, + }; + + match x { + None => false, + _ => true, + }; + + // Don't lint + match x { + Some(21) => true, + _ => false, + }; +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr index 7c5a047e455..a69eb390520 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr @@ -77,49 +77,49 @@ LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:59:20 + --> $DIR/redundant_pattern_matching_option.rs:60:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:61:19 + --> $DIR/redundant_pattern_matching_option.rs:62:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:67:12 + --> $DIR/redundant_pattern_matching_option.rs:68:12 | LL | if let Some(..) = gen_opt() {} | -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:82:12 + --> $DIR/redundant_pattern_matching_option.rs:83:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:84:12 + --> $DIR/redundant_pattern_matching_option.rs:85:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:86:15 + --> $DIR/redundant_pattern_matching_option.rs:87:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:88:15 + --> $DIR/redundant_pattern_matching_option.rs:89:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:90:5 + --> $DIR/redundant_pattern_matching_option.rs:91:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -128,7 +128,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:95:5 + --> $DIR/redundant_pattern_matching_option.rs:96:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -137,16 +137,52 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:103:12 + --> $DIR/redundant_pattern_matching_option.rs:104:12 | LL | if let None = *(&None::<()>) {} | -------^^^^----------------- help: try this: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:104:12 + --> $DIR/redundant_pattern_matching_option.rs:105:12 | LL | if let None = *&None::<()> {} | -------^^^^--------------- help: try this: `if (&None::<()>).is_none()` -error: aborting due to 22 previous errors +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:111:5 + | +LL | / match x { +LL | | Some(_) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `x.is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:116:5 + | +LL | / match x { +LL | | None => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `x.is_none()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:121:5 + | +LL | / match x { +LL | | Some(_) => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `x.is_none()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:126:5 + | +LL | / match x { +LL | | None => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `x.is_some()` + +error: aborting due to 26 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed index c48d1522935..e4032ae44b7 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed @@ -43,6 +43,7 @@ fn main() { issue5504(); issue6067(); issue6065(); + issue10726(); let _ = if gen_res().is_ok() { 1 @@ -107,3 +108,28 @@ const fn issue6067() { Err::<i32, i32>(42).is_err(); } + +fn issue10726() { + // This is optional, but it makes the examples easier + let x: Result<i32, i32> = Ok(42); + + x.is_ok(); + + x.is_err(); + + x.is_err(); + + x.is_ok(); + + // Don't lint + match x { + Err(16) => false, + _ => true, + }; + + // Don't lint + match x { + Ok(16) => false, + _ => true, + }; +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs index 26f37d169fa..39eb10df878 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs @@ -55,6 +55,7 @@ fn main() { issue5504(); issue6067(); issue6065(); + issue10726(); let _ = if let Ok(_) = gen_res() { 1 @@ -125,3 +126,40 @@ const fn issue6067() { Err(_) => true, }; } + +fn issue10726() { + // This is optional, but it makes the examples easier + let x: Result<i32, i32> = Ok(42); + + match x { + Ok(_) => true, + _ => false, + }; + + match x { + Ok(_) => false, + _ => true, + }; + + match x { + Err(_) => true, + _ => false, + }; + + match x { + Err(_) => false, + _ => true, + }; + + // Don't lint + match x { + Err(16) => false, + _ => true, + }; + + // Don't lint + match x { + Ok(16) => false, + _ => true, + }; +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr index d6a46babb77..5893ae4dcc4 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr @@ -73,67 +73,67 @@ LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:59:20 + --> $DIR/redundant_pattern_matching_result.rs:60:20 | LL | let _ = if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:61:19 + --> $DIR/redundant_pattern_matching_result.rs:62:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:84:19 + --> $DIR/redundant_pattern_matching_result.rs:85:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:85:16 + --> $DIR/redundant_pattern_matching_result.rs:86:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:91:12 + --> $DIR/redundant_pattern_matching_result.rs:92:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:92:15 + --> $DIR/redundant_pattern_matching_result.rs:93:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:110:12 + --> $DIR/redundant_pattern_matching_result.rs:111:12 | LL | if let Ok(_) = Ok::<i32, i32>(42) {} | -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:112:12 + --> $DIR/redundant_pattern_matching_result.rs:113:12 | LL | if let Err(_) = Err::<i32, i32>(42) {} | -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:114:15 + --> $DIR/redundant_pattern_matching_result.rs:115:15 | LL | while let Ok(_) = Ok::<i32, i32>(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:116:15 + --> $DIR/redundant_pattern_matching_result.rs:117:15 | LL | while let Err(_) = Ok::<i32, i32>(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:118:5 + --> $DIR/redundant_pattern_matching_result.rs:119:5 | LL | / match Ok::<i32, i32>(42) { LL | | Ok(_) => true, @@ -142,7 +142,7 @@ LL | | }; | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:123:5 + --> $DIR/redundant_pattern_matching_result.rs:124:5 | LL | / match Err::<i32, i32>(42) { LL | | Ok(_) => false, @@ -150,5 +150,41 @@ LL | | Err(_) => true, LL | | }; | |_____^ help: try this: `Err::<i32, i32>(42).is_err()` -error: aborting due to 22 previous errors +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching_result.rs:134:5 + | +LL | / match x { +LL | | Ok(_) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `x.is_ok()` + +error: redundant pattern matching, consider using `is_err()` + --> $DIR/redundant_pattern_matching_result.rs:139:5 + | +LL | / match x { +LL | | Ok(_) => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `x.is_err()` + +error: redundant pattern matching, consider using `is_err()` + --> $DIR/redundant_pattern_matching_result.rs:144:5 + | +LL | / match x { +LL | | Err(_) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `x.is_err()` + +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching_result.rs:149:5 + | +LL | / match x { +LL | | Err(_) => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `x.is_ok()` + +error: aborting due to 26 previous errors diff --git a/src/tools/clippy/tests/ui/ref_patterns.rs b/src/tools/clippy/tests/ui/ref_patterns.rs new file mode 100644 index 00000000000..c51e0bc76ef --- /dev/null +++ b/src/tools/clippy/tests/ui/ref_patterns.rs @@ -0,0 +1,19 @@ +#![allow(unused)] +#![warn(clippy::ref_patterns)] + +fn use_in_pattern() { + let opt = Some(5); + match opt { + None => {}, + Some(ref opt) => {}, + } +} + +fn use_in_binding() { + let x = 5; + let ref y = x; +} + +fn use_in_parameter(ref x: i32) {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/ref_patterns.stderr b/src/tools/clippy/tests/ui/ref_patterns.stderr new file mode 100644 index 00000000000..aa007782683 --- /dev/null +++ b/src/tools/clippy/tests/ui/ref_patterns.stderr @@ -0,0 +1,27 @@ +error: usage of ref pattern + --> $DIR/ref_patterns.rs:8:14 + | +LL | Some(ref opt) => {}, + | ^^^^^^^ + | + = help: consider using `&` for clarity instead + = note: `-D clippy::ref-patterns` implied by `-D warnings` + +error: usage of ref pattern + --> $DIR/ref_patterns.rs:14:9 + | +LL | let ref y = x; + | ^^^^^ + | + = help: consider using `&` for clarity instead + +error: usage of ref pattern + --> $DIR/ref_patterns.rs:17:21 + | +LL | fn use_in_parameter(ref x: i32) {} + | ^^^^^ + | + = help: consider using `&` for clarity instead + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs index ab8ac97a0e7..a5f79b139bc 100644 --- a/src/tools/clippy/tests/ui/regex.rs +++ b/src/tools/clippy/tests/ui/regex.rs @@ -34,8 +34,10 @@ fn syntax_error() { let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]); let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]); + // These following three cases are considering valid since regex-1.8.0 let raw_string_error = Regex::new(r"[...\/...]"); let raw_string_error = Regex::new(r#"[...\/...]"#); + let _ = Regex::new(r"(?<hi>hi)").unwrap(); let escaped_string_span = Regex::new("\\b\\c"); diff --git a/src/tools/clippy/tests/ui/regex.stderr b/src/tools/clippy/tests/ui/regex.stderr index c2440f39e0a..6b8a772e7f0 100644 --- a/src/tools/clippy/tests/ui/regex.stderr +++ b/src/tools/clippy/tests/ui/regex.stderr @@ -82,23 +82,11 @@ error: regex parse error: LL | let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]); | ^^^^^^^^^^^^^ -error: regex syntax error: unrecognized escape sequence - --> $DIR/regex.rs:37:45 - | -LL | let raw_string_error = Regex::new(r"[...//...]"); - | ^^ - -error: regex syntax error: unrecognized escape sequence - --> $DIR/regex.rs:38:46 - | -LL | let raw_string_error = Regex::new(r#"[...//...]"#); - | ^^ - error: regex parse error: /b/c ^^ error: unrecognized escape sequence - --> $DIR/regex.rs:40:42 + --> $DIR/regex.rs:42:42 | LL | let escaped_string_span = Regex::new("/b/c"); | ^^^^^^^^ @@ -106,13 +94,13 @@ LL | let escaped_string_span = Regex::new("/b/c"); = help: consider using a raw string literal: `r".."` error: regex syntax error: duplicate flag - --> $DIR/regex.rs:42:34 + --> $DIR/regex.rs:44:34 | LL | let aux_span = Regex::new("(?ixi)"); | ^ ^ error: trivial regex - --> $DIR/regex.rs:46:33 + --> $DIR/regex.rs:48:33 | LL | let trivial_eq = Regex::new("^foobar$"); | ^^^^^^^^^^ @@ -120,7 +108,7 @@ LL | let trivial_eq = Regex::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:48:48 + --> $DIR/regex.rs:50:48 | LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); | ^^^^^^^^^^ @@ -128,7 +116,7 @@ LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:50:42 + --> $DIR/regex.rs:52:42 | LL | let trivial_starts_with = Regex::new("^foobar"); | ^^^^^^^^^ @@ -136,7 +124,7 @@ LL | let trivial_starts_with = Regex::new("^foobar"); = help: consider using `str::starts_with` error: trivial regex - --> $DIR/regex.rs:52:40 + --> $DIR/regex.rs:54:40 | LL | let trivial_ends_with = Regex::new("foobar$"); | ^^^^^^^^^ @@ -144,7 +132,7 @@ LL | let trivial_ends_with = Regex::new("foobar$"); = help: consider using `str::ends_with` error: trivial regex - --> $DIR/regex.rs:54:39 + --> $DIR/regex.rs:56:39 | LL | let trivial_contains = Regex::new("foobar"); | ^^^^^^^^ @@ -152,7 +140,7 @@ LL | let trivial_contains = Regex::new("foobar"); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:56:39 + --> $DIR/regex.rs:58:39 | LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); | ^^^^^^^^^^^^^^^^ @@ -160,7 +148,7 @@ LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:58:40 + --> $DIR/regex.rs:60:40 | LL | let trivial_backslash = Regex::new("a/.b"); | ^^^^^^^ @@ -168,7 +156,7 @@ LL | let trivial_backslash = Regex::new("a/.b"); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:61:36 + --> $DIR/regex.rs:63:36 | LL | let trivial_empty = Regex::new(""); | ^^ @@ -176,7 +164,7 @@ LL | let trivial_empty = Regex::new(""); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:63:36 + --> $DIR/regex.rs:65:36 | LL | let trivial_empty = Regex::new("^"); | ^^^ @@ -184,7 +172,7 @@ LL | let trivial_empty = Regex::new("^"); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:65:36 + --> $DIR/regex.rs:67:36 | LL | let trivial_empty = Regex::new("^$"); | ^^^^ @@ -192,12 +180,12 @@ LL | let trivial_empty = Regex::new("^$"); = help: consider using `str::is_empty` error: trivial regex - --> $DIR/regex.rs:67:44 + --> $DIR/regex.rs:69:44 | LL | let binary_trivial_empty = BRegex::new("^$"); | ^^^^ | = help: consider using `str::is_empty` -error: aborting due to 25 previous errors +error: aborting due to 23 previous errors diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index 42a59f6d43d..dfe45dec8a7 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -16,6 +16,7 @@ #![allow(clippy::mixed_read_write_in_expression)] #![allow(clippy::useless_conversion)] #![allow(clippy::match_result_ok)] +#![allow(clippy::arithmetic_side_effects)] #![allow(clippy::overly_complex_bool_expr)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] @@ -29,7 +30,11 @@ #![allow(clippy::invisible_characters)] #![allow(suspicious_double_ref_op)] #![allow(drop_bounds)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] #![allow(for_loops_over_fallibles)] +#![allow(forgetting_copy_types)] +#![allow(forgetting_references)] #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] @@ -54,6 +59,7 @@ #![warn(clippy::mixed_read_write_in_expression)] #![warn(clippy::useless_conversion)] #![warn(clippy::match_result_ok)] +#![warn(clippy::arithmetic_side_effects)] #![warn(clippy::overly_complex_bool_expr)] #![warn(clippy::new_without_default)] #![warn(clippy::bind_instead_of_map)] @@ -71,9 +77,13 @@ #![warn(clippy::invisible_characters)] #![warn(suspicious_double_ref_op)] #![warn(drop_bounds)] +#![warn(dropping_copy_types)] +#![warn(dropping_references)] #![warn(for_loops_over_fallibles)] #![warn(for_loops_over_fallibles)] #![warn(for_loops_over_fallibles)] +#![warn(forgetting_copy_types)] +#![warn(forgetting_references)] #![warn(array_into_iter)] #![warn(invalid_atomic_ordering)] #![warn(invalid_value)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index 4d173e8cbbf..ce8eca5a308 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -16,6 +16,7 @@ #![allow(clippy::mixed_read_write_in_expression)] #![allow(clippy::useless_conversion)] #![allow(clippy::match_result_ok)] +#![allow(clippy::arithmetic_side_effects)] #![allow(clippy::overly_complex_bool_expr)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] @@ -29,7 +30,11 @@ #![allow(clippy::invisible_characters)] #![allow(suspicious_double_ref_op)] #![allow(drop_bounds)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] #![allow(for_loops_over_fallibles)] +#![allow(forgetting_copy_types)] +#![allow(forgetting_references)] #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] @@ -54,6 +59,7 @@ #![warn(clippy::eval_order_dependence)] #![warn(clippy::identity_conversion)] #![warn(clippy::if_let_some_result)] +#![warn(clippy::integer_arithmetic)] #![warn(clippy::logic_bug)] #![warn(clippy::new_without_default_derive)] #![warn(clippy::option_and_then_some)] @@ -71,9 +77,13 @@ #![warn(clippy::zero_width_space)] #![warn(clippy::clone_double_ref)] #![warn(clippy::drop_bounds)] +#![warn(clippy::drop_copy)] +#![warn(clippy::drop_ref)] #![warn(clippy::for_loop_over_option)] #![warn(clippy::for_loop_over_result)] #![warn(clippy::for_loops_over_fallibles)] +#![warn(clippy::forget_copy)] +#![warn(clippy::forget_ref)] #![warn(clippy::into_iter_on_array)] #![warn(clippy::invalid_atomic_ordering)] #![warn(clippy::invalid_ref)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 0da4ed7520c..3fca60aa2eb 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,256 +7,286 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` +error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` + --> $DIR/rename.rs:62:9 + | +LL | #![warn(clippy::integer_arithmetic)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` + error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:78:9 | LL | #![warn(clippy::clone_double_ref)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` +error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` + --> $DIR/rename.rs:80:9 + | +LL | #![warn(clippy::drop_copy)] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` + +error: lint `clippy::drop_ref` has been renamed to `dropping_references` + --> $DIR/rename.rs:81:9 + | +LL | #![warn(clippy::drop_ref)] + | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` + error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` +error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` + --> $DIR/rename.rs:85:9 + | +LL | #![warn(clippy::forget_copy)] + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` + +error: lint `clippy::forget_ref` has been renamed to `forgetting_references` + --> $DIR/rename.rs:86:9 + | +LL | #![warn(clippy::forget_ref)] + | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` + error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:87:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:88:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:89:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:90:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:91:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:92:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:83:9 + --> $DIR/rename.rs:93:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:84:9 + --> $DIR/rename.rs:94:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:85:9 + --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:86:9 + --> $DIR/rename.rs:96:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 43 previous errors +error: aborting due to 48 previous errors diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed index eef8024b131..fdac0e4cb1e 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed @@ -2,6 +2,8 @@ #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] +use std::any::Any; + fn bad_foo<T: Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) { unimplemented!(); } @@ -109,4 +111,12 @@ fn qualified_path<T: std::clone::Clone + foo::Clone>(arg0: T) { unimplemented!(); } +fn good_trait_object(arg0: &(dyn Any + Send)) { + unimplemented!(); +} + +fn bad_trait_object(arg0: &(dyn Any + Send)) { + unimplemented!(); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs index a7a1caf2880..a0300da5555 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs @@ -2,6 +2,8 @@ #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] +use std::any::Any; + fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) { unimplemented!(); } @@ -109,4 +111,12 @@ fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) { unimplemented!(); } +fn good_trait_object(arg0: &(dyn Any + Send)) { + unimplemented!(); +} + +fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { + unimplemented!(); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr index af800ba7888..539b6114ca3 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr @@ -1,5 +1,5 @@ error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:5:15 + --> $DIR/trait_duplication_in_bounds.rs:7:15 | LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` @@ -11,46 +11,52 @@ LL | #![deny(clippy::trait_duplication_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:11:8 + --> $DIR/trait_duplication_in_bounds.rs:13:8 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:39:26 + --> $DIR/trait_duplication_in_bounds.rs:41:26 | LL | trait BadSelfTraitBound: Clone + Clone + Clone { | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:46:15 + --> $DIR/trait_duplication_in_bounds.rs:48:15 | LL | Self: Clone + Clone + Clone; | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:60:24 + --> $DIR/trait_duplication_in_bounds.rs:62:24 | LL | trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:67:12 + --> $DIR/trait_duplication_in_bounds.rs:69:12 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:100:19 + --> $DIR/trait_duplication_in_bounds.rs:102:19 | LL | fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait<u64> + GenericTrait<u32>` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:108:22 + --> $DIR/trait_duplication_in_bounds.rs:110:22 | LL | fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone` -error: aborting due to 8 previous errors +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds.rs:118:33 + | +LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { + | ^^^^^^^^^^^^^^^^^ help: try: `Any + Send` + +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed b/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed index 0c269d650c8..49c0e4dc7eb 100644 --- a/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed +++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed @@ -10,7 +10,7 @@ #[warn(clippy::unnecessary_cast)] #[warn(clippy::useless_transmute)] // Shouldn't suggest rustc lint name(`dead_code`) -#[warn(clippy::drop_copy)] +#[warn(clippy::eq_op)] // Shouldn't suggest removed/deprecated clippy lint name(`unused_collect`) #[warn(clippy::unused_self)] // Shouldn't suggest renamed clippy lint name(`const_static_lifetime`) diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr index 421bf5ffa9a..584c428932f 100644 --- a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr +++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr @@ -34,7 +34,7 @@ error: unknown lint: `clippy::dead_cod` --> $DIR/unknown_clippy_lints.rs:13:8 | LL | #[warn(clippy::dead_cod)] - | ^^^^^^^^^^^^^^^^ help: did you mean: `clippy::drop_copy` + | ^^^^^^^^^^^^^^^^ help: did you mean: `clippy::eq_op` error: unknown lint: `clippy::unused_colle` --> $DIR/unknown_clippy_lints.rs:15:8 diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index 01eb6c5b080..c16caa38fe9 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -33,6 +33,11 @@ fn test_issue_3913() -> Result<(), std::io::Error> { Ok(()) } +fn dont_lint_on_type_alias() { + type A = i32; + _ = A::from(0i32); +} + fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() { let text = "foo\r\nbar\n\nbaz\n"; let lines = text.lines(); @@ -106,6 +111,7 @@ fn main() { test_questionmark().unwrap(); test_issue_3913().unwrap(); + dont_lint_on_type_alias(); dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr(); lint_into_iter_on_mutable_local_implementing_iterator_in_expr(); lint_into_iter_on_expr_implementing_iterator(); diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index 34b43a6299b..c75a2bce4ca 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -33,6 +33,11 @@ fn test_issue_3913() -> Result<(), std::io::Error> { Ok(()) } +fn dont_lint_on_type_alias() { + type A = i32; + _ = A::from(0i32); +} + fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() { let text = "foo\r\nbar\n\nbaz\n"; let lines = text.lines(); @@ -106,6 +111,7 @@ fn main() { test_questionmark().unwrap(); test_issue_3913().unwrap(); + dont_lint_on_type_alias(); dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr(); lint_into_iter_on_mutable_local_implementing_iterator_in_expr(); lint_into_iter_on_expr_implementing_iterator(); diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr index be067c6843a..4dca3aac533 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion.stderr @@ -23,97 +23,97 @@ LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:45:22 + --> $DIR/useless_conversion.rs:50:22 | LL | if Some("ok") == lines.into_iter().next() {} | ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:50:21 + --> $DIR/useless_conversion.rs:55:21 | LL | let mut lines = text.lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:56:22 + --> $DIR/useless_conversion.rs:61:22 | LL | if Some("ok") == text.lines().into_iter().next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::ops::Range<i32>` - --> $DIR/useless_conversion.rs:62:13 + --> $DIR/useless_conversion.rs:67:13 | LL | let _ = NUMBERS.into_iter().next(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::ops::Range<i32>` - --> $DIR/useless_conversion.rs:67:17 + --> $DIR/useless_conversion.rs:72:17 | LL | let mut n = NUMBERS.into_iter(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:128:21 + --> $DIR/useless_conversion.rs:134:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:129:21 + --> $DIR/useless_conversion.rs:135:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:130:13 + --> $DIR/useless_conversion.rs:136:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:131:13 + --> $DIR/useless_conversion.rs:137:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:132:13 + --> $DIR/useless_conversion.rs:138:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter<i32>` - --> $DIR/useless_conversion.rs:133:13 + --> $DIR/useless_conversion.rs:139:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:134:21 + --> $DIR/useless_conversion.rs:140:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> $DIR/useless_conversion.rs:139:13 + --> $DIR/useless_conversion.rs:145:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` error: useless conversion to the same type: `Foo<'a'>` - --> $DIR/useless_conversion.rs:145:23 + --> $DIR/useless_conversion.rs:151: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:147:13 + --> $DIR/useless_conversion.rs:153: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:149:13 + --> $DIR/useless_conversion.rs:155:13 | LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` diff --git a/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs b/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs new file mode 100644 index 00000000000..203c4e15b50 --- /dev/null +++ b/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs @@ -0,0 +1,19 @@ +//@compile-flags: --test + +#![warn(clippy::wildcard_imports)] +#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] + +// Test for #10580, the lint should ignore it because of the crate's cfg test flag. + +fn foofoo() {} + +mod outer { + mod inner { + use super::super::*; + fn barbar() { + let _ = foofoo(); + } + } +} + +fn main() {} diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index 3f8f6a7b98c..c40b71f6ca7 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -17,9 +17,9 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB [assign.owners] "/.github" = ["@flip1995"] +"/book" = ["@flip1995"] "/util/gh-pages" = ["@xFrednet"] "*" = [ - "@flip1995", "@Manishearth", "@llogiq", "@giraffate", diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 0d42504c7f4..e5297d41a61 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -20,6 +20,7 @@ once_cell = "1.16.0" walkdir = "2" glob = "0.3.0" lazycell = "1.3.0" +anyhow = "1" [target.'cfg(unix)'.dependencies] libc = "0.2" diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 9059a145b43..ba68b5ee9d5 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -428,7 +428,6 @@ impl TargetCfgs { )) .unwrap(); - let mut current = None; let mut all_targets = HashSet::new(); let mut all_archs = HashSet::new(); let mut all_oses = HashSet::new(); @@ -449,14 +448,11 @@ impl TargetCfgs { } all_pointer_widths.insert(format!("{}bit", cfg.pointer_width)); - if target == config.target { - current = Some(cfg); - } all_targets.insert(target.into()); } Self { - current: current.expect("current target not found"), + current: Self::get_current_target_config(config), all_targets, all_archs, all_oses, @@ -467,6 +463,89 @@ impl TargetCfgs { all_pointer_widths, } } + + fn get_current_target_config(config: &Config) -> TargetCfg { + let mut arch = None; + let mut os = None; + let mut env = None; + let mut abi = None; + let mut families = Vec::new(); + let mut pointer_width = None; + let mut endian = None; + let mut panic = None; + + for config in + rustc_output(config, &["--print=cfg", "--target", &config.target]).trim().lines() + { + let (name, value) = config + .split_once("=\"") + .map(|(name, value)| { + ( + name, + Some( + value + .strip_suffix("\"") + .expect("key-value pair should be properly quoted"), + ), + ) + }) + .unwrap_or_else(|| (config, None)); + + match name { + "target_arch" => { + arch = Some(value.expect("target_arch should be a key-value pair").to_string()); + } + "target_os" => { + os = Some(value.expect("target_os sould be a key-value pair").to_string()); + } + "target_env" => { + env = Some(value.expect("target_env should be a key-value pair").to_string()); + } + "target_abi" => { + abi = Some(value.expect("target_abi should be a key-value pair").to_string()); + } + "target_family" => { + families + .push(value.expect("target_family should be a key-value pair").to_string()); + } + "target_pointer_width" => { + pointer_width = Some( + value + .expect("target_pointer_width should be a key-value pair") + .parse::<u32>() + .expect("target_pointer_width should be a valid u32"), + ); + } + "target_endian" => { + endian = Some(match value.expect("target_endian should be a key-value pair") { + "big" => Endian::Big, + "little" => Endian::Little, + _ => panic!("target_endian should be either 'big' or 'little'"), + }); + } + "panic" => { + panic = Some(match value.expect("panic should be a key-value pair") { + "abort" => PanicStrategy::Abort, + "unwind" => PanicStrategy::Unwind, + _ => panic!("panic should be either 'abort' or 'unwind'"), + }); + } + _ => (), + } + } + + TargetCfg { + arch: arch.expect("target configuration should specify target_arch"), + os: os.expect("target configuration should specify target_os"), + env: env.expect("target configuration should specify target_env"), + abi: abi.expect("target configuration should specify target_abi"), + families, + pointer_width: pointer_width + .expect("target configuration should specify target_pointer_width"), + endian: endian.expect("target configuration should specify target_endian"), + panic: panic.expect("target configuration should specify panic"), + } + } } #[derive(Clone, Debug, serde::Deserialize)] diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 4ede4603789..5bc4d164265 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -32,6 +32,7 @@ use std::process::{Child, Command, ExitStatus, Output, Stdio}; use std::str; use std::sync::Arc; +use anyhow::Context; use glob::glob; use once_cell::sync::Lazy; use tracing::*; @@ -131,7 +132,11 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) { } let cx = TestCx { config: &config, props: &props, testpaths, revision }; - create_dir_all(&cx.output_base_dir()).unwrap(); + create_dir_all(&cx.output_base_dir()) + .with_context(|| { + format!("failed to create output base directory {}", cx.output_base_dir().display()) + }) + .unwrap(); if props.incremental { cx.init_incremental_test(); } diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 4170c32f1fe..c8a370085a0 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -139,18 +139,18 @@ enum FileEntry { type Cache = HashMap<String, FileEntry>; fn small_url_encode(s: &str) -> String { - s.replace("<", "%3C") - .replace(">", "%3E") - .replace(" ", "%20") - .replace("?", "%3F") - .replace("'", "%27") - .replace("&", "%26") - .replace(",", "%2C") - .replace(":", "%3A") - .replace(";", "%3B") - .replace("[", "%5B") - .replace("]", "%5D") - .replace("\"", "%22") + s.replace('<', "%3C") + .replace('>', "%3E") + .replace(' ', "%20") + .replace('?', "%3F") + .replace('\'', "%27") + .replace('&', "%26") + .replace(',', "%2C") + .replace(':', "%3A") + .replace(';', "%3B") + .replace('[', "%5B") + .replace(']', "%5D") + .replace('\"', "%22") } impl Checker { @@ -267,7 +267,6 @@ impl Checker { 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 => { @@ -391,7 +390,7 @@ impl Checker { const ERROR_INVALID_NAME: i32 = 123; let pretty_path = - file.strip_prefix(&self.root).unwrap_or(&file).to_str().unwrap().to_string(); + 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) { @@ -470,10 +469,8 @@ fn is_exception(file: &Path, link: &str) -> bool { // 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; - } + if file.ends_with("std/primitive.slice.html") && link.ends_with("primitive.slice.html") { + return true; } false } @@ -545,7 +542,7 @@ fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(source: &str, attr: &str, m 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 frag = fragment.trim_start_matches('#').to_owned(); let encoded = small_url_encode(&frag); if !ids.insert(frag) { report.errors += 1; diff --git a/src/tools/miri/Cargo.lock b/src/tools/miri/Cargo.lock index e2a7d484c23..737423a2cd1 100644 --- a/src/tools/miri/Cargo.lock +++ b/src/tools/miri/Cargo.lock @@ -820,9 +820,9 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.9.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95033b0e41b8018013d99a6f1486c1ae5bd080378ced60c5f797e93842423b33" +checksum = "191a442639ea102fa62671026047e51d574bfda44b7fdf32151d7314624c1cd2" dependencies = [ "bstr", "cargo-platform", diff --git a/src/tools/miri/Cargo.toml b/src/tools/miri/Cargo.toml index f6f81836804..5987b0df8d6 100644 --- a/src/tools/miri/Cargo.toml +++ b/src/tools/miri/Cargo.toml @@ -39,7 +39,7 @@ libloading = "0.7" [dev-dependencies] colored = "2" -ui_test = "0.9" +ui_test = "0.10" rustc_version = "0.4" # Features chosen to match those required by env_logger, to avoid rebuilds regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } diff --git a/src/tools/miri/ci.sh b/src/tools/miri/ci.sh index 76cc2e94927..b5b3b211b05 100755 --- a/src/tools/miri/ci.sh +++ b/src/tools/miri/ci.sh @@ -45,8 +45,7 @@ function run_tests { # them. Also error locations change so we don't run the failing tests. # We explicitly enable debug-assertions here, they are disabled by -O but we have tests # which exist to check that we panic on debug assertion failures. - #FIXME: Disabled due to <https://github.com/rust-lang/rust/issues/111422>. - #MIRIFLAGS="${MIRIFLAGS:-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} + MIRIFLAGS="${MIRIFLAGS:-} -O -Zmir-opt-level=4 -Cdebug-assertions=yes" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} # Also run some many-seeds tests. 64 seeds means this takes around a minute per test. for FILE in tests/many-seeds/*.rs; do diff --git a/src/tools/miri/miri b/src/tools/miri/miri index 4be970b398d..48a46a76a12 100755 --- a/src/tools/miri/miri +++ b/src/tools/miri/miri @@ -306,7 +306,7 @@ test|bless) # Only in root project as `cargo-miri` has no tests. $CARGO test $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" ;; -run) +run|run-dep) # Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so # that we set the MIRI_SYSROOT up the right way. FOUND_TARGET_OPT=0 @@ -323,11 +323,17 @@ run) # Make sure Miri actually uses this target. MIRIFLAGS="$MIRIFLAGS --target $MIRI_TEST_TARGET" fi + # First build and get a sysroot. $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot # Then run the actual command. - exec $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- $MIRIFLAGS "$@" + + if [ "$COMMAND" = "run-dep" ]; then + exec $CARGO test --test compiletest $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --miri-run-dep-mode $MIRIFLAGS "$@" + else + exec $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- $MIRIFLAGS "$@" + fi ;; fmt) find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version index 25304fc19f7..b450f986149 100644 --- a/src/tools/miri/rust-version +++ b/src/tools/miri/rust-version @@ -1 +1 @@ -65dfca8488d635552eb246eb8e15df646e987cff +69fef92ab2f287f072b66fb7b4f62c8bb4acba43 diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 28f9912e283..083dd4800d9 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -28,8 +28,8 @@ use rustc_middle::{ middle::exported_symbols::{ ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, }, - query::LocalCrate, - ty::{query::ExternProviders, TyCtxt}, + query::{ExternProviders, LocalCrate}, + ty::TyCtxt, }; use rustc_session::config::OptLevel; diff --git a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs index 064dbe025af..a1e949183ad 100644 --- a/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs +++ b/src/tools/miri/src/borrow_tracker/stacked_borrows/stack.rs @@ -83,7 +83,7 @@ impl Stack { self.borrows.truncate(write_idx); #[cfg(not(feature = "stack-cache"))] - drop(first_removed); // This is only needed for the stack-cache + let _unused = first_removed; // This is only needed for the stack-cache #[cfg(feature = "stack-cache")] if let Some(first_removed) = first_removed { diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs index a93f3eb84f2..e3f81a78eea 100644 --- a/src/tools/miri/src/diagnostics.rs +++ b/src/tools/miri/src/diagnostics.rs @@ -289,7 +289,7 @@ pub fn report_error<'tcx, 'mir>( (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")), ], InvalidProgram( - InvalidProgramInfo::AlreadyReported(rustc_errors::ErrorGuaranteed { .. }) + InvalidProgramInfo::AlreadyReported(_) ) => { // This got already reported. No point in reporting it again. return None; diff --git a/src/tools/miri/src/lib.rs b/src/tools/miri/src/lib.rs index fc938080a0e..893a4dbd4c8 100644 --- a/src/tools/miri/src/lib.rs +++ b/src/tools/miri/src/lib.rs @@ -47,7 +47,6 @@ extern crate rustc_ast; extern crate rustc_middle; extern crate rustc_const_eval; extern crate rustc_data_structures; -extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_index; extern crate rustc_session; diff --git a/src/tools/miri/src/shims/intrinsics/simd.rs b/src/tools/miri/src/shims/intrinsics/simd.rs index d101f8d3111..114c66253f7 100644 --- a/src/tools/miri/src/shims/intrinsics/simd.rs +++ b/src/tools/miri/src/shims/intrinsics/simd.rs @@ -421,14 +421,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { } } #[rustfmt::skip] - "cast" | "as" => { + "cast" | "as" | "cast_ptr" | "expose_addr" | "from_exposed_addr" => { let [op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.place_to_simd(dest)?; assert_eq!(dest_len, op_len); + let unsafe_cast = intrinsic_name == "cast"; let safe_cast = intrinsic_name == "as"; + let ptr_cast = intrinsic_name == "cast_ptr"; + let expose_cast = intrinsic_name == "expose_addr"; + let from_exposed_cast = intrinsic_name == "from_exposed_addr"; for i in 0..dest_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; @@ -436,19 +440,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> { let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) { // Int-to-(int|float): always safe - (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) => + (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) if safe_cast || unsafe_cast => this.int_to_int_or_float(&op, dest.layout.ty)?, // Float-to-float: always safe - (ty::Float(_), ty::Float(_)) => + (ty::Float(_), ty::Float(_)) if safe_cast || unsafe_cast => this.float_to_float_or_int(&op, dest.layout.ty)?, // Float-to-int in safe mode (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast => this.float_to_float_or_int(&op, dest.layout.ty)?, // Float-to-int in unchecked mode - (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if !safe_cast => + (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if unsafe_cast => this.float_to_int_unchecked(op.to_scalar().to_f32()?, dest.layout.ty)?.into(), - (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if !safe_cast => + (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if unsafe_cast => this.float_to_int_unchecked(op.to_scalar().to_f64()?, dest.layout.ty)?.into(), + // Ptr-to-ptr cast + (ty::RawPtr(..), ty::RawPtr(..)) if ptr_cast => { + this.ptr_to_ptr(&op, dest.layout.ty)? + } + // Ptr/Int casts + (ty::RawPtr(..), ty::Int(_) | ty::Uint(_)) if expose_cast => { + this.pointer_expose_address_cast(&op, dest.layout.ty)? + } + (ty::Int(_) | ty::Uint(_), ty::RawPtr(..)) if from_exposed_cast => { + this.pointer_from_exposed_address_cast(&op, dest.layout.ty)? + } + // Error otherwise _ => throw_unsup_format!( "Unsupported SIMD cast from element type {from_ty} to {to_ty}", diff --git a/src/tools/miri/tests/compiletest.rs b/src/tools/miri/tests/compiletest.rs index fe70ab3f45a..fa06c4b6a12 100644 --- a/src/tools/miri/tests/compiletest.rs +++ b/src/tools/miri/tests/compiletest.rs @@ -1,5 +1,6 @@ use colored::*; use regex::bytes::Regex; +use std::ffi::OsString; use std::path::{Path, PathBuf}; use std::{env, process::Command}; use ui_test::status_emitter::StatusEmitter; @@ -45,7 +46,7 @@ fn build_so_for_c_ffi_tests() -> PathBuf { so_file_path } -fn run_tests(mode: Mode, path: &str, target: &str, with_dependencies: bool) -> Result<()> { +fn test_config(target: &str, path: &str, mode: Mode, with_dependencies: bool) -> Config { // Miri is rustc-like, so we create a default builder for rustc and modify it let mut program = CommandBuilder::rustc(); program.program = miri_path(); @@ -103,6 +104,26 @@ fn run_tests(mode: Mode, path: &str, target: &str, with_dependencies: bool) -> R ..Config::default() }; + let use_std = env::var_os("MIRI_NO_STD").is_none(); + + if with_dependencies && use_std { + config.dependencies_crate_manifest_path = + Some(Path::new("test_dependencies").join("Cargo.toml")); + config.dependency_builder.args = vec![ + "run".into(), + "--manifest-path".into(), + "cargo-miri/Cargo.toml".into(), + "--".into(), + "miri".into(), + "run".into(), // There is no `cargo miri build` so we just use `cargo miri run`. + ]; + } + config +} + +fn run_tests(mode: Mode, path: &str, target: &str, with_dependencies: bool) -> Result<()> { + let mut config = test_config(target, path, mode, with_dependencies); + // Handle command-line arguments. let mut after_dashdash = false; config.path_filter.extend(std::env::args().skip(1).filter(|arg| { @@ -126,20 +147,7 @@ fn run_tests(mode: Mode, path: &str, target: &str, with_dependencies: bool) -> R } })); - let use_std = env::var_os("MIRI_NO_STD").is_none(); - - if with_dependencies && use_std { - config.dependencies_crate_manifest_path = - Some(Path::new("test_dependencies").join("Cargo.toml")); - config.dependency_builder.args = vec![ - "run".into(), - "--manifest-path".into(), - "cargo-miri/Cargo.toml".into(), - "--".into(), - "miri".into(), - "run".into(), // There is no `cargo miri build` so we just use `cargo miri run`. - ]; - } + eprintln!(" Compiler: {}", config.program.display()); ui_test::run_tests_generic( config, // The files we're actually interested in (all `.rs` files). @@ -224,8 +232,18 @@ fn get_target() -> String { fn main() -> Result<()> { ui_test::color_eyre::install()?; + let target = get_target(); + let mut args = std::env::args_os(); + + // Skip the program name and check whether this is a `./miri run-dep` invocation + if let Some(first) = args.nth(1) { + if first == "--miri-run-dep-mode" { + return run_dep_mode(target, args); + } + } + // Add a test env var to do environment communication tests. env::set_var("MIRI_ENV_VAR_TEST", "0"); // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). @@ -248,6 +266,21 @@ fn main() -> Result<()> { Ok(()) } +fn run_dep_mode(target: String, mut args: impl Iterator<Item = OsString>) -> Result<()> { + let path = args.next().expect("./miri run-dep must be followed by a file name"); + let mut config = test_config(&target, "", Mode::Yolo, /* with dependencies */ true); + config.program.args.remove(0); // remove the `--error-format=json` argument + config.program.args.push("--color".into()); + config.program.args.push("always".into()); + let mut cmd = ui_test::test_command(config, Path::new(&path))?; + // Separate the arguments to the `cargo miri` invocation from + // the arguments to the interpreted prog + cmd.arg("--"); + cmd.args(args); + println!("{cmd:?}"); + if cmd.spawn()?.wait()?.success() { Ok(()) } else { std::process::exit(1) } +} + /// This is a custom renderer for `ui_test` output that does not emit github actions /// `group`s, while still producing regular github actions messages on test failures. struct TextAndGha; diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs b/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs index 606a6b2798a..98b6749c584 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs +++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.rs @@ -5,7 +5,8 @@ fn main() { unsafe { let mut vec: Vec<i8> = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; let idxs = Simd::from_array([9, 3, 0, 17]); - Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( //~ERROR: pointer to 1 byte starting at offset 9 is out-of-bounds + Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( + //~^ERROR: pointer to 1 byte starting at offset 9 is out-of-bounds &mut vec, Mask::splat(true), idxs, diff --git a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr index 6d959af85fa..a745b61029d 100644 --- a/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr +++ b/src/tools/miri/tests/fail/intrinsics/simd-scatter.stderr @@ -2,6 +2,7 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 9, so po --> $DIR/simd-scatter.rs:LL:CC | LL | / Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( +LL | | LL | | &mut vec, LL | | Mask::splat(true), LL | | idxs, diff --git a/src/tools/miri/tests/fail/never_say_never.rs b/src/tools/miri/tests/fail/never_say_never.rs index f6d3dc790bf..fd082e367a8 100644 --- a/src/tools/miri/tests/fail/never_say_never.rs +++ b/src/tools/miri/tests/fail/never_say_never.rs @@ -6,10 +6,8 @@ fn main() { let y = &5; - let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR: entering unreachable code - }; - f(x) + let x: ! = unsafe { *(y as *const _ as *const !) }; + f(x) //~ ERROR: entering unreachable code } fn f(x: !) -> ! { diff --git a/src/tools/miri/tests/fail/never_say_never.stderr b/src/tools/miri/tests/fail/never_say_never.stderr index a2a63b8baf5..9d3a8df525a 100644 --- a/src/tools/miri/tests/fail/never_say_never.stderr +++ b/src/tools/miri/tests/fail/never_say_never.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: entering unreachable code --> $DIR/never_say_never.rs:LL:CC | -LL | *(y as *const _ as *const !) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code +LL | f(x) + | ^^^^ entering unreachable code | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/src/tools/miri/tests/fail/stacked_borrows/illegal_write2.rs b/src/tools/miri/tests/fail/stacked_borrows/illegal_write2.rs index 70c51e671fe..a5a1930ed65 100644 --- a/src/tools/miri/tests/fail/stacked_borrows/illegal_write2.rs +++ b/src/tools/miri/tests/fail/stacked_borrows/illegal_write2.rs @@ -1,3 +1,5 @@ +#![allow(dropping_references)] + fn main() { let target = &mut 42; let target2 = target as *mut _; diff --git a/src/tools/miri/tests/fail/uninit_buffer.rs b/src/tools/miri/tests/fail/uninit_buffer.rs index 8819c53a4f9..d622b2fa7d8 100644 --- a/src/tools/miri/tests/fail/uninit_buffer.rs +++ b/src/tools/miri/tests/fail/uninit_buffer.rs @@ -1,5 +1,7 @@ //@error-in-other-file: memory is uninitialized at [0x4..0x10] +#![allow(dropping_copy_types)] + use std::alloc::{alloc, dealloc, Layout}; use std::slice::from_raw_parts; diff --git a/src/tools/miri/tests/fail/uninit_buffer_with_provenance.rs b/src/tools/miri/tests/fail/uninit_buffer_with_provenance.rs index e788c079cb4..ca825901372 100644 --- a/src/tools/miri/tests/fail/uninit_buffer_with_provenance.rs +++ b/src/tools/miri/tests/fail/uninit_buffer_with_provenance.rs @@ -1,6 +1,7 @@ //@error-in-other-file: memory is uninitialized at [0x4..0x8] //@normalize-stderr-test: "a[0-9]+" -> "ALLOC" #![feature(strict_provenance)] +#![allow(dropping_copy_types)] // Test printing allocations that contain single-byte provenance. diff --git a/src/tools/miri/tests/pass/portable-simd-ptrs.rs b/src/tools/miri/tests/pass/portable-simd-ptrs.rs new file mode 100644 index 00000000000..303c99834f5 --- /dev/null +++ b/src/tools/miri/tests/pass/portable-simd-ptrs.rs @@ -0,0 +1,12 @@ +// Separate test without strict provenance +//@compile-flags: -Zmiri-permissive-provenance +#![feature(portable_simd, platform_intrinsics)] +use std::ptr; +use std::simd::*; + +fn main() { + // Pointer casts + let _val: Simd<*const u8, 4> = Simd::<*const i32, 4>::splat(ptr::null()).cast_ptr(); + let addrs = Simd::<*const i32, 4>::splat(ptr::null()).expose_addr(); + let _ptrs = Simd::<*const i32, 4>::from_exposed_addr(addrs); +} diff --git a/src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs b/src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs index ce3c8b7d5f1..6e13a9ea836 100644 --- a/src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs +++ b/src/tools/miri/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs @@ -1,5 +1,8 @@ //@compile-flags: -Zmiri-retag-fields // Checks that the test does not run forever (which relies on a fast path). + +#![allow(dropping_copy_types)] + fn main() { let array = [(); usize::MAX]; drop(array); // Pass the array to a function, retagging its fields diff --git a/src/tools/replace-version-placeholder/src/main.rs b/src/tools/replace-version-placeholder/src/main.rs index 0aebfc4aad2..5c9c18b9b36 100644 --- a/src/tools/replace-version-placeholder/src/main.rs +++ b/src/tools/replace-version-placeholder/src/main.rs @@ -8,15 +8,13 @@ fn main() { let version_path = root_path.join("src").join("version"); let version_str = t!(std::fs::read_to_string(&version_path), version_path); let version_str = version_str.trim(); - walk::walk( - &root_path, + walk::walk_many( + &[&root_path.join("compiler"), &root_path.join("library")], |path, _is_dir| { walk::filter_dirs(path) // We exempt these as they require the placeholder // for their operation || path.ends_with("compiler/rustc_attr/src/builtin.rs") - || path.ends_with("src/tools/tidy/src/features/version.rs") - || path.ends_with("src/tools/replace-version-placeholder") }, &mut |entry, contents| { if !contents.contains(VERSION_PLACEHOLDER) { diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index afa6bce943f..2e778110931 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -117,6 +117,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "autocfg", "bitflags", "block-buffer", + "byteorder", // via ruzstd in object in thorin-dwp "cc", "cfg-if", "chalk-derive", @@ -145,6 +146,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "expect-test", "fallible-iterator", // dependency of `thorin` "fastrand", + "field-offset", "fixedbitset", "flate2", "fluent-bundle", @@ -216,6 +218,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "rustc-rayon", "rustc-rayon-core", "rustc_version", + "ruzstd", // via object in thorin-dwp "ryu", "scoped-tls", "scopeguard", diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index 5f388ee47bb..d0257d71697 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -296,6 +296,12 @@ pub fn check(path: &Path, bad: &mut bool) { if filename.contains("ignore-tidy") { return; } + // Shell completions are automatically generated + if let Some(p) = file.parent() { + if p.ends_with(Path::new("src/etc/completions")) { + return; + } + } // apfloat shouldn't be changed because of license problems if is_in(file, "compiler", "rustc_apfloat") { return; diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 9473eabe442..be3a5d3aa0f 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -4,13 +4,39 @@ use ignore::Walk; use std::collections::HashMap; +use std::ffi::OsStr; use std::fs; use std::path::{Path, PathBuf}; const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. const ISSUES_ENTRY_LIMIT: usize = 1920; -const ROOT_ENTRY_LIMIT: usize = 895; +const ROOT_ENTRY_LIMIT: usize = 896; + +const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ + "rs", // test source files + "stderr", // expected stderr file, corresponds to a rs file + "stdout", // expected stdout file, corresponds to a rs file + "fixed", // expected source file after applying fixes + "md", // test directory descriptions + "ftl", // translation tests +]; + +const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ + "tests/ui/asm/named-asm-labels.s", // loading an external asm file to test named labels lint + "tests/ui/check-cfg/my-awesome-platform.json", // testing custom targets with cfgs + "tests/ui/commandline-argfile-badutf8.args", // passing args via a file + "tests/ui/commandline-argfile.args", // passing args via a file + "tests/ui/crate-loading/auxiliary/libfoo.rlib", // testing loading a manually created rlib + "tests/ui/include-macros/data.bin", // testing including data with the include macros + "tests/ui/include-macros/file.txt", // testing including data with the include macros + "tests/ui/macros/macro-expanded-include/file.txt", // testing including data with the include macros + "tests/ui/macros/not-utf8.bin", // testing including data with the include macros + "tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include + "tests/ui/unused-crate-deps/test.mk", // why would you use make + "tests/ui/proc-macro/auxiliary/included-file.txt", // more include + "tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer +]; fn check_entries(tests_path: &Path, bad: &mut bool) { let mut directories: HashMap<PathBuf, usize> = HashMap::new(); @@ -66,7 +92,14 @@ pub fn check(path: &Path, bad: &mut bool) { let paths = [ui.as_path(), ui_fulldeps.as_path()]; crate::walk::walk_no_read(&paths, |_, _| false, &mut |entry| { let file_path = entry.path(); - if let Some(ext) = file_path.extension() { + if let Some(ext) = file_path.extension().and_then(OsStr::to_str) { + // files that are neither an expected extension or an exception should not exist + // they're probably typos or not meant to exist + if !(EXPECTED_TEST_FILE_EXTENSIONS.contains(&ext) + || EXTENSION_EXCEPTION_PATHS.iter().any(|path| file_path.ends_with(path))) + { + tidy_error!(bad, "file {} has unexpected extension {}", file_path.display(), ext); + } if ext == "stderr" || ext == "stdout" { // Test output filenames have one of the formats: // ``` diff --git a/tests/codegen/addr-of-mutate.rs b/tests/codegen/addr-of-mutate.rs new file mode 100644 index 00000000000..bea1aad2352 --- /dev/null +++ b/tests/codegen/addr-of-mutate.rs @@ -0,0 +1,34 @@ +// compile-flags: -C opt-level=3 -C no-prepopulate-passes +// min-llvm-version: 15.0 (for opaque pointers) + +#![crate_type = "lib"] + +// Test for the absence of `readonly` on the argument when it is mutated via `&raw const`. +// See <https://github.com/rust-lang/rust/issues/111502>. + +// CHECK: i8 @foo(ptr noalias nocapture noundef dereferenceable(128) %x) +#[no_mangle] +pub fn foo(x: [u8; 128]) -> u8 { + let ptr = core::ptr::addr_of!(x).cast_mut(); + unsafe { + (*ptr)[0] = 1; + } + x[0] +} + +// CHECK: i1 @second(ptr noalias nocapture noundef dereferenceable({{[0-9]+}}) %a_ptr_and_b) +#[no_mangle] +pub unsafe fn second(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { + let b_bool_ptr = core::ptr::addr_of!(a_ptr_and_b.1.1).cast_mut(); + (*b_bool_ptr) = true; + a_ptr_and_b.1.1 +} + +// If going through a deref (and there are no other mutating accesses), then `readonly` is fine. +// CHECK: i1 @third(ptr noalias nocapture noundef readonly dereferenceable({{[0-9]+}}) %a_ptr_and_b) +#[no_mangle] +pub unsafe fn third(a_ptr_and_b: (*mut (i32, bool), (i64, bool))) -> bool { + let b_bool_ptr = core::ptr::addr_of!((*a_ptr_and_b.0).1).cast_mut(); + (*b_bool_ptr) = true; + a_ptr_and_b.1.1 +} diff --git a/tests/codegen/binary-search-index-no-bound-check.rs b/tests/codegen/binary-search-index-no-bound-check.rs index c1766a4a44a..595969a8979 100644 --- a/tests/codegen/binary-search-index-no-bound-check.rs +++ b/tests/codegen/binary-search-index-no-bound-check.rs @@ -9,7 +9,9 @@ #[no_mangle] pub fn binary_search_index_no_bounds_check(s: &[u8]) -> u8 { // CHECK-NOT: panic - // CHECK-NOT: slice_index_len_fail + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check if let Ok(idx) = s.binary_search(&b'\\') { s[idx] } else { diff --git a/tests/codegen/fewer-names.rs b/tests/codegen/fewer-names.rs index df1080bff2b..a09c795924c 100644 --- a/tests/codegen/fewer-names.rs +++ b/tests/codegen/fewer-names.rs @@ -13,8 +13,8 @@ pub fn sum(x: u32, y: u32) -> u32 { // NO-LABEL: define{{.*}}i32 @sum(i32 noundef %x, i32 noundef %y) // NO-NEXT: start: - // NO-NEXT: %z = add i32 %y, %x - // NO-NEXT: ret i32 %z + // NO-NEXT: %0 = add i32 %y, %x + // NO-NEXT: ret i32 %0 let z = x + y; z } diff --git a/tests/codegen/issues/issue-111603.rs b/tests/codegen/issues/issue-111603.rs new file mode 100644 index 00000000000..90b3c314d2f --- /dev/null +++ b/tests/codegen/issues/issue-111603.rs @@ -0,0 +1,28 @@ +// compile-flags: -O + +#![crate_type = "lib"] +#![feature(get_mut_unchecked, new_uninit)] + +use std::sync::Arc; + +// CHECK-LABEL: @new_uninit +#[no_mangle] +pub fn new_uninit(x: u64) -> Arc<[u64; 1000]> { + // CHECK: call alloc::sync::arcinner_layout_for_value_layout + // CHECK-NOT: call alloc::sync::arcinner_layout_for_value_layout + let mut arc = Arc::new_uninit(); + unsafe { Arc::get_mut_unchecked(&mut arc) }.write([x; 1000]); + unsafe { arc.assume_init() } +} + +// CHECK-LABEL: @new_uninit_slice +#[no_mangle] +pub fn new_uninit_slice(x: u64) -> Arc<[u64]> { + // CHECK: call alloc::sync::arcinner_layout_for_value_layout + // CHECK-NOT: call alloc::sync::arcinner_layout_for_value_layout + let mut arc = Arc::new_uninit_slice(1000); + for elem in unsafe { Arc::get_mut_unchecked(&mut arc) } { + elem.write(x); + } + unsafe { arc.assume_init() } +} diff --git a/tests/codegen/issues/issue-73396-bounds-check-after-position.rs b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs index 8d07a67a1b4..2d779788791 100644 --- a/tests/codegen/issues/issue-73396-bounds-check-after-position.rs +++ b/tests/codegen/issues/issue-73396-bounds-check-after-position.rs @@ -9,7 +9,10 @@ #[no_mangle] pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { // CHECK-NOT: panic - // CHECK-NOT: slice_index_len_fail + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: unreachable if let Some(idx) = s.iter().position(|b| *b == b'\\') { &s[..idx] } else { @@ -21,7 +24,10 @@ pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { #[no_mangle] pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { // CHECK-NOT: panic - // CHECK-NOT: slice_index_len_fail + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: unreachable if let Some(idx) = s.iter().position(|b| *b == b'\\') { &s[idx..] } else { @@ -33,7 +39,10 @@ pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { #[no_mangle] pub fn position_index_no_bounds_check(s: &[u8]) -> u8 { // CHECK-NOT: panic - // CHECK-NOT: slice_index_len_fail + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: unreachable if let Some(idx) = s.iter().position(|b| *b == b'\\') { s[idx] } else { @@ -44,7 +53,10 @@ pub fn position_index_no_bounds_check(s: &[u8]) -> u8 { #[no_mangle] pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { // CHECK-NOT: panic - // CHECK-NOT: slice_index_len_fail + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: unreachable if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { &s[..idx] } else { @@ -56,7 +68,10 @@ pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { #[no_mangle] pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { // CHECK-NOT: panic - // CHECK-NOT: slice_index_len_fail + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: unreachable if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { &s[idx..] } else { @@ -68,7 +83,10 @@ pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { #[no_mangle] pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 { // CHECK-NOT: panic - // CHECK-NOT: slice_index_len_fail + // CHECK-NOT: slice_start_index_len_fail + // CHECK-NOT: slice_end_index_len_fail + // CHECK-NOT: panic_bounds_check + // CHECK-NOT: unreachable if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { s[idx] } else { diff --git a/tests/codegen/mem-replace-big-type.rs b/tests/codegen/mem-replace-big-type.rs index acf759ebe54..c6b920cf599 100644 --- a/tests/codegen/mem-replace-big-type.rs +++ b/tests/codegen/mem-replace-big-type.rs @@ -13,8 +13,7 @@ pub struct Big([u64; 7]); pub fn replace_big(dst: &mut Big, src: Big) -> Big { // Back in 1.68, this emitted six `memcpy`s. // `read_via_copy` in 1.69 got that down to three. - // `write_via_move` it was originally down to the essential two, however - // with nrvo disabled it is back at 3 + // `write_via_move` and nvro get this down to the essential two. std::mem::replace(dst, src) } @@ -26,11 +25,9 @@ pub fn replace_big(dst: &mut Big, src: Big) -> Big { // For a large type, we expect exactly three `memcpy`s // CHECK-LABEL: define internal void @{{.+}}mem{{.+}}replace{{.+}}sret(%Big) // CHECK-NOT: call void @llvm.memcpy -// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %result, {{i8\*|ptr}} align 8 %dest, i{{.*}} 56, i1 false) +// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %0, {{i8\*|ptr}} align 8 %dest, i{{.*}} 56, i1 false) // CHECK-NOT: call void @llvm.memcpy // CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %dest, {{i8\*|ptr}} align 8 %src, i{{.*}} 56, i1 false) // CHECK-NOT: call void @llvm.memcpy -// CHECK: call void @llvm.memcpy.{{.+}}({{i8\*|ptr}} align 8 %0, {{i8\*|ptr}} align 8 %result, i{{.*}} 56, i1 false) -// CHECK-NOT: call void @llvm.memcpy // CHECK-NOT: call void @llvm.memcpy diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs index 71e26e3fe8a..3aa16d9f645 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs +++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-id-itanium-cxx-abi.rs @@ -44,7 +44,7 @@ impl<T> Trait1<T> for i32 { } // Trait implementation -impl<T> Trait1<T> for Struct1<T> { +impl<T, U> Trait1<T> for Struct1<U> { fn foo(&self) { } } @@ -536,15 +536,15 @@ pub fn foo149(_: Type14<Bar>, _: Type14<Bar>, _: Type14<Bar>) { } // CHECK: ![[TYPE93]] = !{i64 0, !"_ZTSFvPFu3i32S_EE"} // CHECK: ![[TYPE94]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_E"} // CHECK: ![[TYPE95]] = !{i64 0, !"_ZTSFvPFu3i32S_ES0_S0_E"} -// CHECK: ![[TYPE96]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} -// CHECK: ![[TYPE97]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} -// CHECK: ![[TYPE98]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} -// CHECK: ![[TYPE99]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} -// CHECK: ![[TYPE100]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} -// CHECK: ![[TYPE101]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} -// CHECK: ![[TYPE102]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEEE"} -// CHECK: ![[TYPE103]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_E"} -// CHECK: ![[TYPE104]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5tupleIu3i32EEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIS0_ES_u6regionEES5_S5_E"} +// CHECK: ![[TYPE96]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIu5tupleIu3i32EES1_u6regionEEE"} +// CHECK: ![[TYPE97]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIu5tupleIu3i32EES1_u6regionEES6_E"} +// CHECK: ![[TYPE98]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function2FnIu5paramEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIu5tupleIu3i32EES1_u6regionEES6_S6_E"} +// CHECK: ![[TYPE99]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIu5tupleIu3i32EES1_u6regionEEE"} +// CHECK: ![[TYPE100]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIu5tupleIu3i32EES1_u6regionEES6_E"} +// CHECK: ![[TYPE101]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function5FnMutIu5paramEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIu5tupleIu3i32EES1_u6regionEES6_S6_E"} +// CHECK: ![[TYPE102]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIu5tupleIu3i32EES1_u6regionEEE"} +// CHECK: ![[TYPE103]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIu5tupleIu3i32EES1_u6regionEES6_E"} +// CHECK: ![[TYPE104]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnceIu5paramEu{{[0-9]+}}NtNtNtNtC{{[[:print:]]+}}_4core3ops8function6FnOnce6OutputIu5tupleIu3i32EES1_u6regionEES6_S6_E"} // CHECK: ![[TYPE105]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEEE"} // CHECK: ![[TYPE106]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_E"} // CHECK: ![[TYPE107]] = !{i64 0, !"_ZTSFvu3refIu3dynIu{{[0-9]+}}NtNtC{{[[:print:]]+}}_4core6marker4Sendu6regionEES2_S2_E"} @@ -566,9 +566,9 @@ pub fn foo149(_: Type14<Bar>, _: Type14<Bar>, _: Type14<Bar>) { } // CHECK: ![[TYPE123]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32EE"} // CHECK: ![[TYPE124]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_E"} // CHECK: ![[TYPE125]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNINvC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi3fn18{{[{}][{}]}}impl{{[}][}]}}3fooIu3i32ES0_S0_E"} -// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_EE"} -// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_E"} -// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu3i32Eu6regionES_ES3_S3_E"} +// CHECK: ![[TYPE126]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu5paramEu6regionEu3i32EE"} +// CHECK: ![[TYPE127]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu5paramEu6regionEu3i32ES4_E"} +// CHECK: ![[TYPE128]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3dynIu{{[0-9]+}}NtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait1Iu5paramEu6regionEu3i32ES4_S4_E"} // CHECK: ![[TYPE129]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_EE"} // CHECK: ![[TYPE130]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_E"} // CHECK: ![[TYPE131]] = !{i64 0, !"_ZTSFvu{{[0-9]+}}NvNtC{{[[:print:]]+}}_51sanitizer_cfi_emit_type_metadata_id_itanium_cxx_abi6Trait13fooIu3i32S_ES0_S0_E"} diff --git a/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs index ab5dcec7936..18914049a10 100644 --- a/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs +++ b/tests/codegen/sanitizer-cfi-emit-type-metadata-trait-objects.rs @@ -1,44 +1,89 @@ // Verifies that type metadata identifiers for trait objects are emitted correctly. // // needs-sanitizer-cfi -// compile-flags: -Clto -Cno-prepopulate-passes -Ctarget-feature=-crt-static -Zsanitizer=cfi +// compile-flags: -Clto -Cno-prepopulate-passes -Copt-level=0 -Ctarget-feature=-crt-static -Zsanitizer=cfi #![crate_type="lib"] -trait Trait1 { +pub trait Trait1 { fn foo(&self); } -struct Type1; +#[derive(Clone, Copy)] +pub struct Type1; impl Trait1 for Type1 { fn foo(&self) { } } -pub fn foo() { - let a = Type1; +pub trait Trait2<T> { + fn bar(&self); +} + +pub struct Type2; + +impl Trait2<i32> for Type2 { + fn bar(&self) { + } +} + +pub trait Trait3<T> { + fn baz(&self, _: &T); +} + +pub struct Type3; + +impl<T, U> Trait3<U> for T { + fn baz(&self, _: &U) { + } +} + +pub fn foo1(a: &dyn Trait1) { a.foo(); - // CHECK-LABEL: define{{.*}}foo{{.*}}!type !{{[0-9]+}} - // CHECK: call <sanitizer_cfi_emit_type_metadata_trait_objects::Type1 as sanitizer_cfi_emit_type_metadata_trait_objects::Trait1>::foo + // CHECK-LABEL: define{{.*}}4foo1{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE1:[[:print:]]+]]") } -pub fn bar() { +pub fn bar1() { let a = Type1; let b = &a as &dyn Trait1; b.foo(); - // CHECK-LABEL: define{{.*}}bar{{.*}}!type !{{[0-9]+}} - // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0|%1}}, metadata !"[[TYPE1:[[:print:]]+]]") + // CHECK-LABEL: define{{.*}}4bar1{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]") } -pub fn baz() { - let a = Type1; - let b = &a as &dyn Trait1; - a.foo(); - b.foo(); - // CHECK-LABEL: define{{.*}}baz{{.*}}!type !{{[0-9]+}} - // CHECK: call <sanitizer_cfi_emit_type_metadata_trait_objects::Type1 as sanitizer_cfi_emit_type_metadata_trait_objects::Trait1>::foo - // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%0|%1}}, metadata !"[[TYPE1:[[:print:]]+]]") +pub fn foo2<T>(a: &dyn Trait2<T>) { + a.bar(); + // CHECK-LABEL: define{{.*}}4foo2{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]") +} + +pub fn bar2() { + let a = Type2; + foo2(&a); + let b = &a as &dyn Trait2<i32>; + b.bar(); + // CHECK-LABEL: define{{.*}}4bar2{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE2:[[:print:]]+]]") +} + +pub fn foo3(a: &dyn Trait3<Type3>) { + let b = Type3; + a.baz(&b); + // CHECK-LABEL: define{{.*}}4foo3{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]") +} + +pub fn bar3() { + let a = Type3; + foo3(&a); + let b = &a as &dyn Trait3<Type3>; + b.baz(&a); + // CHECK-LABEL: define{{.*}}4bar3{{.*}}!type !{{[0-9]+}} + // CHECK: call i1 @llvm.type.test({{i8\*|ptr}} {{%f|%[0-9]}}, metadata !"[[TYPE3:[[:print:]]+]]") } // CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE1]]"} +// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE2]]"} +// CHECK: !{{[0-9]+}} = !{i64 0, !"[[TYPE3]]"} diff --git a/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs b/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs index 81e0d9344f7..a46f0955696 100644 --- a/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs +++ b/tests/codegen/sanitizer-kcfi-emit-type-metadata-trait-objects.rs @@ -30,40 +30,84 @@ trait Freeze { } #[lang="drop_in_place"] fn drop_in_place_fn<T>() { } -trait Trait1 { +pub trait Trait1 { fn foo(&self); } -struct Type1; +pub struct Type1; impl Trait1 for Type1 { fn foo(&self) { } } -pub fn foo() { - let a = Type1; +pub trait Trait2<T> { + fn bar(&self); +} + +pub struct Type2; + +impl Trait2<i32> for Type2 { + fn bar(&self) { + } +} + +pub trait Trait3<T> { + fn baz(&self, _: &T); +} + +pub struct Type3; + +impl<T, U> Trait3<U> for T { + fn baz(&self, _: &U) { + } +} + +pub fn foo1(a: &dyn Trait1) { a.foo(); - // CHECK-LABEL: define{{.*}}foo{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} - // CHECK: call <sanitizer_kcfi_emit_type_metadata_trait_objects::Type1 as sanitizer_kcfi_emit_type_metadata_trait_objects::Trait1>::foo + // CHECK-LABEL: define{{.*}}4foo1{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] } -pub fn bar() { +pub fn bar1() { let a = Type1; let b = &a as &dyn Trait1; b.foo(); - // CHECK-LABEL: define{{.*}}bar{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} - // CHECK: call void %0({{\{\}\*|ptr}} align 1 {{%b\.0|%_1}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] + // CHECK-LABEL: define{{.*}}4bar1{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] } -pub fn baz() { - let a = Type1; - let b = &a as &dyn Trait1; - a.foo(); - b.foo(); - // CHECK-LABEL: define{{.*}}baz{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} - // CHECK: call <sanitizer_kcfi_emit_type_metadata_trait_objects::Type1 as sanitizer_kcfi_emit_type_metadata_trait_objects::Trait1>::foo - // CHECK: call void %0({{\{\}\*|ptr}} align 1 {{%b\.0|%_1}}){{.*}}[ "kcfi"(i32 [[TYPE1:[[:print:]]+]]) ] +pub fn foo2<T>(a: &dyn Trait2<T>) { + a.bar(); + // CHECK-LABEL: define{{.*}}4foo2{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ] +} + +pub fn bar2() { + let a = Type2; + foo2(&a); + let b = &a as &dyn Trait2<i32>; + b.bar(); + // CHECK-LABEL: define{{.*}}4bar2{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE2:[[:print:]]+]]) ] +} + +pub fn foo3(a: &dyn Trait3<Type3>) { + let b = Type3; + a.baz(&b); + // CHECK-LABEL: define{{.*}}4foo3{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}, {{\{\}\*|ptr|%Type3\*}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ] +} + +pub fn bar3() { + let a = Type3; + foo3(&a); + let b = &a as &dyn Trait3<Type3>; + b.baz(&a); + // CHECK-LABEL: define{{.*}}4bar3{{.*}}!{{<unknown kind #36>|kcfi_type}} !{{[0-9]+}} + // CHECK: call void %{{[0-9]}}({{\{\}\*|ptr}} align 1 {{%[a-z]\.0|%_[0-9]}}, {{\{\}\*|ptr|%Type3\*}} align 1 {{%[a-z]\.0|%_[0-9]}}){{.*}}[ "kcfi"(i32 [[TYPE3:[[:print:]]+]]) ] } // CHECK: !{{[0-9]+}} = !{i32 [[TYPE1]]} +// CHECK: !{{[0-9]+}} = !{i32 [[TYPE2]]} +// CHECK: !{{[0-9]+}} = !{i32 [[TYPE3]]} diff --git a/tests/codegen/slice-iter-nonnull.rs b/tests/codegen/slice-iter-nonnull.rs index 392e4338076..997bdaf5636 100644 --- a/tests/codegen/slice-iter-nonnull.rs +++ b/tests/codegen/slice-iter-nonnull.rs @@ -40,3 +40,38 @@ pub fn slice_iter_next_back<'a>(it: &mut std::slice::Iter<'a, u32>) -> Option<&' it.next_back() } + +// The slice iterator `new` methods used to `assume` that the pointer is non-null, +// but passing slices already requires that, to the extent that LLVM actually +// removed the `call @llvm.assume` anyway. These tests just demonstrate that the +// attribute is there, and confirms adding the assume back doesn't do anything. + +// CHECK-LABEL: @slice_iter_new +// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef %slice.1) +#[no_mangle] +pub fn slice_iter_new(slice: &[u32]) -> std::slice::Iter<'_, u32> { + // CHECK-NOT: slice + // CHECK: %[[END:.+]] = getelementptr inbounds i32{{.+}} %slice.0{{.+}} %slice.1 + // CHECK-NOT: slice + // CHECK: insertvalue {{.+}} ptr %slice.0, 0 + // CHECK-NOT: slice + // CHECK: insertvalue {{.+}} ptr %[[END]], 1 + // CHECK-NOT: slice + // CHECK: } + slice.iter() +} + +// CHECK-LABEL: @slice_iter_mut_new +// CHECK-SAME: (ptr noalias noundef nonnull {{.+}} %slice.0, {{.+}} noundef %slice.1) +#[no_mangle] +pub fn slice_iter_mut_new(slice: &mut [u32]) -> std::slice::IterMut<'_, u32> { + // CHECK-NOT: slice + // CHECK: %[[END:.+]] = getelementptr inbounds i32{{.+}} %slice.0{{.+}} %slice.1 + // CHECK-NOT: slice + // CHECK: insertvalue {{.+}} ptr %slice.0, 0 + // CHECK-NOT: slice + // CHECK: insertvalue {{.+}} ptr %[[END]], 1 + // CHECK-NOT: slice + // CHECK: } + slice.iter_mut() +} diff --git a/tests/codegen/var-names.rs b/tests/codegen/var-names.rs index d4715efad73..53841df32e8 100644 --- a/tests/codegen/var-names.rs +++ b/tests/codegen/var-names.rs @@ -9,7 +9,7 @@ pub fn test(a: u32, b: u32) -> u32 { // CHECK: %c = add i32 %a, %b let d = c; let e = d * a; - // CHECK-NEXT: %e = mul i32 %c, %a + // CHECK-NEXT: %0 = mul i32 %c, %a e - // CHECK-NEXT: ret i32 %e + // CHECK-NEXT: ret i32 %0 } diff --git a/tests/debuginfo/reference-debuginfo.rs b/tests/debuginfo/reference-debuginfo.rs new file mode 100644 index 00000000000..85ade170ac6 --- /dev/null +++ b/tests/debuginfo/reference-debuginfo.rs @@ -0,0 +1,173 @@ +// Copy of `borrowed-basic.rs` which enables the `ReferencePropagation` MIR pass. +// That pass replaces debuginfo for `a => _x` where `_x = &b` to be `a => &b`, +// and leaves codegen to create a ladder of allocations so as `*a == b`. +// +// compile-flags:-g -Zmir-enable-passes=+ReferencePropagation,-ConstDebugInfo +// min-lldb-version: 310 + +// === GDB TESTS =================================================================================== + +// gdb-command:run +// gdb-command:print *bool_ref +// gdb-check:$1 = true + +// gdb-command:print *int_ref +// gdb-check:$2 = -1 + +// gdb-command:print/d *char_ref +// gdb-check:$3 = 97 + +// gdb-command:print *i8_ref +// gdbg-check:$4 = 68 'D' +// gdbr-check:$4 = 68 + +// gdb-command:print *i16_ref +// gdb-check:$5 = -16 + +// gdb-command:print *i32_ref +// gdb-check:$6 = -32 + +// gdb-command:print *i64_ref +// gdb-check:$7 = -64 + +// gdb-command:print *uint_ref +// gdb-check:$8 = 1 + +// gdb-command:print *u8_ref +// gdbg-check:$9 = 100 'd' +// gdbr-check:$9 = 100 + +// gdb-command:print *u16_ref +// gdb-check:$10 = 16 + +// gdb-command:print *u32_ref +// gdb-check:$11 = 32 + +// gdb-command:print *u64_ref +// gdb-check:$12 = 64 + +// gdb-command:print *f32_ref +// gdb-check:$13 = 2.5 + +// gdb-command:print *f64_ref +// gdb-check:$14 = 3.5 + +// gdb-command:print *f64_double_ref +// gdb-check:$15 = 3.5 + + +// === LLDB TESTS ================================================================================== + +// lldb-command:run +// lldb-command:print *bool_ref +// lldbg-check:[...]$0 = true +// lldbr-check:(bool) *bool_ref = true + +// lldb-command:print *int_ref +// lldbg-check:[...]$1 = -1 +// lldbr-check:(isize) *int_ref = -1 + +// NOTE: only rust-enabled lldb supports 32bit chars +// lldbr-command:print *char_ref +// lldbr-check:(char) *char_ref = 'a' + +// lldb-command:print *i8_ref +// lldbg-check:[...]$2 = 'D' +// lldbr-check:(i8) *i8_ref = 68 + +// lldb-command:print *i16_ref +// lldbg-check:[...]$3 = -16 +// lldbr-check:(i16) *i16_ref = -16 + +// lldb-command:print *i32_ref +// lldbg-check:[...]$4 = -32 +// lldbr-check:(i32) *i32_ref = -32 + +// lldb-command:print *i64_ref +// lldbg-check:[...]$5 = -64 +// lldbr-check:(i64) *i64_ref = -64 + +// lldb-command:print *uint_ref +// lldbg-check:[...]$6 = 1 +// lldbr-check:(usize) *uint_ref = 1 + +// lldb-command:print *u8_ref +// lldbg-check:[...]$7 = 'd' +// lldbr-check:(u8) *u8_ref = 100 + +// lldb-command:print *u16_ref +// lldbg-check:[...]$8 = 16 +// lldbr-check:(u16) *u16_ref = 16 + +// lldb-command:print *u32_ref +// lldbg-check:[...]$9 = 32 +// lldbr-check:(u32) *u32_ref = 32 + +// lldb-command:print *u64_ref +// lldbg-check:[...]$10 = 64 +// lldbr-check:(u64) *u64_ref = 64 + +// lldb-command:print *f32_ref +// lldbg-check:[...]$11 = 2.5 +// lldbr-check:(f32) *f32_ref = 2.5 + +// lldb-command:print *f64_ref +// lldbg-check:[...]$12 = 3.5 +// lldbr-check:(f64) *f64_ref = 3.5 + +// lldb-command:print *f64_double_ref +// lldbg-check:[...]$13 = 3.5 +// lldbr-check:(f64) **f64_double_ref = 3.5 + +#![allow(unused_variables)] +#![feature(omit_gdb_pretty_printer_section)] +#![omit_gdb_pretty_printer_section] + +fn main() { + let bool_val: bool = true; + let bool_ref: &bool = &bool_val; + + let int_val: isize = -1; + let int_ref: &isize = &int_val; + + let char_val: char = 'a'; + let char_ref: &char = &char_val; + + let i8_val: i8 = 68; + let i8_ref: &i8 = &i8_val; + + let i16_val: i16 = -16; + let i16_ref: &i16 = &i16_val; + + let i32_val: i32 = -32; + let i32_ref: &i32 = &i32_val; + + let i64_val: i64 = -64; + let i64_ref: &i64 = &i64_val; + + let uint_val: usize = 1; + let uint_ref: &usize = &uint_val; + + let u8_val: u8 = 100; + let u8_ref: &u8 = &u8_val; + + let u16_val: u16 = 16; + let u16_ref: &u16 = &u16_val; + + let u32_val: u32 = 32; + let u32_ref: &u32 = &u32_val; + + let u64_val: u64 = 64; + let u64_ref: &u64 = &u64_val; + + let f32_val: f32 = 2.5; + let f32_ref: &f32 = &f32_val; + + let f64_val: f64 = 3.5; + let f64_ref: &f64 = &f64_val; + let f64_double_ref: &f64 = &f64_ref; + + zzz(); // #break +} + +fn zzz() {()} diff --git a/tests/incremental/const-generic-type-cycle.rs b/tests/incremental/const-generic-type-cycle.rs new file mode 100644 index 00000000000..ca7b12e9e62 --- /dev/null +++ b/tests/incremental/const-generic-type-cycle.rs @@ -0,0 +1,17 @@ +// Verify that we do not ICE when we try to overwrite an anon-const's type because of a trait +// cycle. +// +// compile-flags: -Zincremental-ignore-spans +// revisions: cpass cfail +// error-pattern: cycle detected when computing type of `Bar::N` + +#![feature(trait_alias)] +#![crate_type="lib"] + +#[cfg(cpass)] +trait Bar<const N: usize> {} + +#[cfg(cfail)] +trait Bar<const N: dyn BB> {} + +trait BB = Bar<{ 2 + 1 }>; diff --git a/tests/mir-opt/building/custom/projections.copy_for_deref.built.after.mir b/tests/mir-opt/building/custom/projections.copy_for_deref.built.after.mir new file mode 100644 index 00000000000..5233d0489c6 --- /dev/null +++ b/tests/mir-opt/building/custom/projections.copy_for_deref.built.after.mir @@ -0,0 +1,12 @@ +// MIR for `copy_for_deref` after built + +fn copy_for_deref(_1: (&i32, i32)) -> i32 { + let mut _0: i32; // return place in scope 0 at $DIR/projections.rs:+0:38: +0:41 + let mut _2: &i32; // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL + + bb0: { + _2 = deref_copy (_1.0: &i32); // scope 0 at $DIR/projections.rs:+4:13: +4:37 + _0 = (*_2); // scope 0 at $DIR/projections.rs:+5:13: +5:24 + return; // scope 0 at $DIR/projections.rs:+6:13: +6:21 + } +} diff --git a/tests/mir-opt/building/custom/projections.rs b/tests/mir-opt/building/custom/projections.rs index 5e472e531c7..3c155deae4b 100644 --- a/tests/mir-opt/building/custom/projections.rs +++ b/tests/mir-opt/building/custom/projections.rs @@ -21,13 +21,10 @@ fn unions(u: U) -> i32 { #[custom_mir(dialect = "analysis", phase = "post-cleanup")] fn tuples(i: (u32, i32)) -> (u32, i32) { mir!( - // FIXME(JakobDegen): This is necessary because we can't give type hints for `RET` - let temp: (u32, i32); + type RET = (u32, i32); { - temp.0 = i.0; - temp.1 = i.1; - - RET = temp; + RET.0 = i.0; + RET.1 = i.1; Return() } ) @@ -71,6 +68,19 @@ fn simple_index(a: [i32; 10], b: &[i32]) -> i32 { }) } +// EMIT_MIR projections.copy_for_deref.built.after.mir +#[custom_mir(dialect = "runtime", phase = "initial")] +fn copy_for_deref(x: (&i32, i32)) -> i32 { + mir!( + let temp: &i32; + { + temp = CopyForDeref(x.0); + RET = *temp; + Return() + } + ) +} + fn main() { assert_eq!(unions(U { a: 5 }), 5); assert_eq!(tuples((5, 6)), (5, 6)); @@ -82,4 +92,7 @@ fn main() { assert_eq!(o, Some(10)); assert_eq!(simple_index([0; 10], &[0; 10]), 0); + + let one = 1; + assert_eq!(copy_for_deref((&one, one)), 1); } diff --git a/tests/mir-opt/building/custom/projections.tuples.built.after.mir b/tests/mir-opt/building/custom/projections.tuples.built.after.mir index 65487d3c9ed..dec575200c6 100644 --- a/tests/mir-opt/building/custom/projections.tuples.built.after.mir +++ b/tests/mir-opt/building/custom/projections.tuples.built.after.mir @@ -2,12 +2,10 @@ fn tuples(_1: (u32, i32)) -> (u32, i32) { let mut _0: (u32, i32); // return place in scope 0 at $DIR/projections.rs:+0:29: +0:39 - let mut _2: (u32, i32); // in scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL bb0: { - (_2.0: u32) = (_1.0: u32); // scope 0 at $DIR/projections.rs:+5:13: +5:25 - (_2.1: i32) = (_1.1: i32); // scope 0 at $DIR/projections.rs:+6:13: +6:25 - _0 = _2; // scope 0 at $DIR/projections.rs:+8:13: +8:23 - return; // scope 0 at $DIR/projections.rs:+9:13: +9:21 + (_0.0: u32) = (_1.0: u32); // scope 0 at $DIR/projections.rs:+4:13: +4:24 + (_0.1: i32) = (_1.1: i32); // scope 0 at $DIR/projections.rs:+5:13: +5:24 + return; // scope 0 at $DIR/projections.rs:+6:13: +6:21 } } diff --git a/tests/mir-opt/combine_transmutes.adt_transmutes.InstSimplify.diff b/tests/mir-opt/combine_transmutes.adt_transmutes.InstSimplify.diff index c5907e7cf18..15117ea890e 100644 --- a/tests/mir-opt/combine_transmutes.adt_transmutes.InstSimplify.diff +++ b/tests/mir-opt/combine_transmutes.adt_transmutes.InstSimplify.diff @@ -4,59 +4,29 @@ fn adt_transmutes() -> () { let mut _0: (); // return place in scope 0 at $DIR/combine_transmutes.rs:+0:32: +0:32 let _1: u8; // in scope 0 at $DIR/combine_transmutes.rs:+1:9: +1:11 - let mut _2: EnumNoRepr; // in scope 0 at $DIR/combine_transmutes.rs:+1:28: +1:41 - let mut _4: EnumNoRepr; // in scope 0 at $DIR/combine_transmutes.rs:+2:28: +2:41 - let mut _6: EnumReprIsize; // in scope 0 at $DIR/combine_transmutes.rs:+3:31: +3:47 - let mut _8: EnumReprIsize; // in scope 0 at $DIR/combine_transmutes.rs:+4:31: +4:47 - let mut _10: std::cmp::Ordering; // in scope 0 at $DIR/combine_transmutes.rs:+5:28: +5:52 - let mut _12: std::cmp::Ordering; // in scope 0 at $DIR/combine_transmutes.rs:+6:28: +6:52 - let mut _14: std::option::Option<std::num::NonZeroU8>; // in scope 0 at $DIR/combine_transmutes.rs:+7:28: +7:58 - let mut _16: std::num::Wrapping<i16>; // in scope 0 at $DIR/combine_transmutes.rs:+8:29: +8:54 - let mut _18: std::num::Wrapping<i16>; // in scope 0 at $DIR/combine_transmutes.rs:+9:29: +9:54 - let mut _20: Union32; // in scope 0 at $DIR/combine_transmutes.rs:+10:29: +10:47 - let mut _22: Union32; // in scope 0 at $DIR/combine_transmutes.rs:+11:29: +11:47 - let mut _24: std::mem::MaybeUninit<std::string::String>; // in scope 0 at $DIR/combine_transmutes.rs:+12:46: +12:77 + let mut _2: std::option::Option<std::num::NonZeroU8>; // in scope 0 at $DIR/combine_transmutes.rs:+1:28: +1:58 + let mut _4: std::num::Wrapping<i16>; // in scope 0 at $DIR/combine_transmutes.rs:+2:29: +2:54 + let mut _6: std::num::Wrapping<i16>; // in scope 0 at $DIR/combine_transmutes.rs:+3:29: +3:54 + let mut _8: Union32; // in scope 0 at $DIR/combine_transmutes.rs:+4:29: +4:47 + let mut _10: Union32; // in scope 0 at $DIR/combine_transmutes.rs:+5:29: +5:47 + let mut _12: std::mem::MaybeUninit<std::string::String>; // in scope 0 at $DIR/combine_transmutes.rs:+6:46: +6:77 scope 1 { debug _a => _1; // in scope 1 at $DIR/combine_transmutes.rs:+1:9: +1:11 - let _3: i8; // in scope 1 at $DIR/combine_transmutes.rs:+2:9: +2:11 + let _3: i16; // in scope 1 at $DIR/combine_transmutes.rs:+2:9: +2:11 scope 2 { debug _a => _3; // in scope 2 at $DIR/combine_transmutes.rs:+2:9: +2:11 - let _5: usize; // in scope 2 at $DIR/combine_transmutes.rs:+3:9: +3:11 + let _5: u16; // in scope 2 at $DIR/combine_transmutes.rs:+3:9: +3:11 scope 3 { debug _a => _5; // in scope 3 at $DIR/combine_transmutes.rs:+3:9: +3:11 - let _7: isize; // in scope 3 at $DIR/combine_transmutes.rs:+4:9: +4:11 + let _7: u32; // in scope 3 at $DIR/combine_transmutes.rs:+4:9: +4:11 scope 4 { debug _a => _7; // in scope 4 at $DIR/combine_transmutes.rs:+4:9: +4:11 - let _9: u8; // in scope 4 at $DIR/combine_transmutes.rs:+5:9: +5:11 + let _9: i32; // in scope 4 at $DIR/combine_transmutes.rs:+5:9: +5:11 scope 5 { debug _a => _9; // in scope 5 at $DIR/combine_transmutes.rs:+5:9: +5:11 - let _11: i8; // in scope 5 at $DIR/combine_transmutes.rs:+6:9: +6:11 + let _11: std::mem::ManuallyDrop<std::string::String>; // in scope 5 at $DIR/combine_transmutes.rs:+6:9: +6:11 scope 6 { debug _a => _11; // in scope 6 at $DIR/combine_transmutes.rs:+6:9: +6:11 - let _13: u8; // in scope 6 at $DIR/combine_transmutes.rs:+7:9: +7:11 - scope 7 { - debug _a => _13; // in scope 7 at $DIR/combine_transmutes.rs:+7:9: +7:11 - let _15: i16; // in scope 7 at $DIR/combine_transmutes.rs:+8:9: +8:11 - scope 8 { - debug _a => _15; // in scope 8 at $DIR/combine_transmutes.rs:+8:9: +8:11 - let _17: u16; // in scope 8 at $DIR/combine_transmutes.rs:+9:9: +9:11 - scope 9 { - debug _a => _17; // in scope 9 at $DIR/combine_transmutes.rs:+9:9: +9:11 - let _19: u32; // in scope 9 at $DIR/combine_transmutes.rs:+10:9: +10:11 - scope 10 { - debug _a => _19; // in scope 10 at $DIR/combine_transmutes.rs:+10:9: +10:11 - let _21: i32; // in scope 10 at $DIR/combine_transmutes.rs:+11:9: +11:11 - scope 11 { - debug _a => _21; // in scope 11 at $DIR/combine_transmutes.rs:+11:9: +11:11 - let _23: std::mem::ManuallyDrop<std::string::String>; // in scope 11 at $DIR/combine_transmutes.rs:+12:9: +12:11 - scope 12 { - debug _a => _23; // in scope 12 at $DIR/combine_transmutes.rs:+12:9: +12:11 - } - } - } - } - } - } } } } @@ -66,93 +36,55 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/combine_transmutes.rs:+1:9: +1:11 - StorageLive(_2); // scope 0 at $DIR/combine_transmutes.rs:+1:28: +1:41 - _2 = EnumNoRepr::A; // scope 0 at $DIR/combine_transmutes.rs:+1:28: +1:41 - _1 = move _2 as u8 (Transmute); // scope 0 at $DIR/combine_transmutes.rs:+1:18: +1:42 - StorageDead(_2); // scope 0 at $DIR/combine_transmutes.rs:+1:41: +1:42 + StorageLive(_2); // scope 0 at $DIR/combine_transmutes.rs:+1:28: +1:58 + _2 = Option::<NonZeroU8>::Some(const _); // scope 0 at $DIR/combine_transmutes.rs:+1:28: +1:58 + // mir::Constant + // + span: $DIR/combine_transmutes.rs:35:33: 35:57 + // + literal: Const { ty: NonZeroU8, val: Unevaluated(NonZeroU8::MAX, [], None) } + _1 = move _2 as u8 (Transmute); // scope 0 at $DIR/combine_transmutes.rs:+1:18: +1:59 + StorageDead(_2); // scope 0 at $DIR/combine_transmutes.rs:+1:58: +1:59 StorageLive(_3); // scope 1 at $DIR/combine_transmutes.rs:+2:9: +2:11 - StorageLive(_4); // scope 1 at $DIR/combine_transmutes.rs:+2:28: +2:41 - _4 = EnumNoRepr::B; // scope 1 at $DIR/combine_transmutes.rs:+2:28: +2:41 - _3 = move _4 as i8 (Transmute); // scope 1 at $DIR/combine_transmutes.rs:+2:18: +2:42 - StorageDead(_4); // scope 1 at $DIR/combine_transmutes.rs:+2:41: +2:42 + StorageLive(_4); // scope 1 at $DIR/combine_transmutes.rs:+2:29: +2:54 + _4 = Wrapping::<i16>(const 0_i16); // scope 1 at $DIR/combine_transmutes.rs:+2:29: +2:54 +- _3 = move _4 as i16 (Transmute); // scope 1 at $DIR/combine_transmutes.rs:+2:19: +2:55 ++ _3 = move (_4.0: i16); // scope 1 at $DIR/combine_transmutes.rs:+2:19: +2:55 + StorageDead(_4); // scope 1 at $DIR/combine_transmutes.rs:+2:54: +2:55 StorageLive(_5); // scope 2 at $DIR/combine_transmutes.rs:+3:9: +3:11 - StorageLive(_6); // scope 2 at $DIR/combine_transmutes.rs:+3:31: +3:47 - _6 = EnumReprIsize::A; // scope 2 at $DIR/combine_transmutes.rs:+3:31: +3:47 - _5 = move _6 as usize (Transmute); // scope 2 at $DIR/combine_transmutes.rs:+3:21: +3:48 - StorageDead(_6); // scope 2 at $DIR/combine_transmutes.rs:+3:47: +3:48 + StorageLive(_6); // scope 2 at $DIR/combine_transmutes.rs:+3:29: +3:54 + _6 = Wrapping::<i16>(const 0_i16); // scope 2 at $DIR/combine_transmutes.rs:+3:29: +3:54 + _5 = move _6 as u16 (Transmute); // scope 2 at $DIR/combine_transmutes.rs:+3:19: +3:55 + StorageDead(_6); // scope 2 at $DIR/combine_transmutes.rs:+3:54: +3:55 StorageLive(_7); // scope 3 at $DIR/combine_transmutes.rs:+4:9: +4:11 - StorageLive(_8); // scope 3 at $DIR/combine_transmutes.rs:+4:31: +4:47 - _8 = EnumReprIsize::B; // scope 3 at $DIR/combine_transmutes.rs:+4:31: +4:47 -- _7 = move _8 as isize (Transmute); // scope 3 at $DIR/combine_transmutes.rs:+4:21: +4:48 -+ _7 = discriminant(_8); // scope 3 at $DIR/combine_transmutes.rs:+4:21: +4:48 + StorageLive(_8); // scope 3 at $DIR/combine_transmutes.rs:+4:29: +4:47 + _8 = Union32 { u32: const 0_i32 }; // scope 3 at $DIR/combine_transmutes.rs:+4:29: +4:47 + _7 = move _8 as u32 (Transmute); // scope 3 at $DIR/combine_transmutes.rs:+4:19: +4:48 StorageDead(_8); // scope 3 at $DIR/combine_transmutes.rs:+4:47: +4:48 StorageLive(_9); // scope 4 at $DIR/combine_transmutes.rs:+5:9: +5:11 - StorageLive(_10); // scope 4 at $DIR/combine_transmutes.rs:+5:28: +5:52 - _10 = Less; // scope 4 at $DIR/combine_transmutes.rs:+5:28: +5:52 - _9 = move _10 as u8 (Transmute); // scope 4 at $DIR/combine_transmutes.rs:+5:18: +5:53 - StorageDead(_10); // scope 4 at $DIR/combine_transmutes.rs:+5:52: +5:53 + StorageLive(_10); // scope 4 at $DIR/combine_transmutes.rs:+5:29: +5:47 + _10 = Union32 { u32: const 0_u32 }; // scope 4 at $DIR/combine_transmutes.rs:+5:29: +5:47 + _9 = move _10 as i32 (Transmute); // scope 4 at $DIR/combine_transmutes.rs:+5:19: +5:48 + StorageDead(_10); // scope 4 at $DIR/combine_transmutes.rs:+5:47: +5:48 StorageLive(_11); // scope 5 at $DIR/combine_transmutes.rs:+6:9: +6:11 - StorageLive(_12); // scope 5 at $DIR/combine_transmutes.rs:+6:28: +6:52 - _12 = Less; // scope 5 at $DIR/combine_transmutes.rs:+6:28: +6:52 -- _11 = move _12 as i8 (Transmute); // scope 5 at $DIR/combine_transmutes.rs:+6:18: +6:53 -+ _11 = discriminant(_12); // scope 5 at $DIR/combine_transmutes.rs:+6:18: +6:53 - StorageDead(_12); // scope 5 at $DIR/combine_transmutes.rs:+6:52: +6:53 - StorageLive(_13); // scope 6 at $DIR/combine_transmutes.rs:+7:9: +7:11 - StorageLive(_14); // scope 6 at $DIR/combine_transmutes.rs:+7:28: +7:58 - _14 = Option::<NonZeroU8>::Some(const _); // scope 6 at $DIR/combine_transmutes.rs:+7:28: +7:58 - // mir::Constant - // + span: $DIR/combine_transmutes.rs:41:33: 41:57 - // + literal: Const { ty: NonZeroU8, val: Unevaluated(NonZeroU8::MAX, [], None) } - _13 = move _14 as u8 (Transmute); // scope 6 at $DIR/combine_transmutes.rs:+7:18: +7:59 - StorageDead(_14); // scope 6 at $DIR/combine_transmutes.rs:+7:58: +7:59 - StorageLive(_15); // scope 7 at $DIR/combine_transmutes.rs:+8:9: +8:11 - StorageLive(_16); // scope 7 at $DIR/combine_transmutes.rs:+8:29: +8:54 - _16 = Wrapping::<i16>(const 0_i16); // scope 7 at $DIR/combine_transmutes.rs:+8:29: +8:54 -- _15 = move _16 as i16 (Transmute); // scope 7 at $DIR/combine_transmutes.rs:+8:19: +8:55 -+ _15 = move (_16.0: i16); // scope 7 at $DIR/combine_transmutes.rs:+8:19: +8:55 - StorageDead(_16); // scope 7 at $DIR/combine_transmutes.rs:+8:54: +8:55 - StorageLive(_17); // scope 8 at $DIR/combine_transmutes.rs:+9:9: +9:11 - StorageLive(_18); // scope 8 at $DIR/combine_transmutes.rs:+9:29: +9:54 - _18 = Wrapping::<i16>(const 0_i16); // scope 8 at $DIR/combine_transmutes.rs:+9:29: +9:54 - _17 = move _18 as u16 (Transmute); // scope 8 at $DIR/combine_transmutes.rs:+9:19: +9:55 - StorageDead(_18); // scope 8 at $DIR/combine_transmutes.rs:+9:54: +9:55 - StorageLive(_19); // scope 9 at $DIR/combine_transmutes.rs:+10:9: +10:11 - StorageLive(_20); // scope 9 at $DIR/combine_transmutes.rs:+10:29: +10:47 - _20 = Union32 { u32: const 0_i32 }; // scope 9 at $DIR/combine_transmutes.rs:+10:29: +10:47 - _19 = move _20 as u32 (Transmute); // scope 9 at $DIR/combine_transmutes.rs:+10:19: +10:48 - StorageDead(_20); // scope 9 at $DIR/combine_transmutes.rs:+10:47: +10:48 - StorageLive(_21); // scope 10 at $DIR/combine_transmutes.rs:+11:9: +11:11 - StorageLive(_22); // scope 10 at $DIR/combine_transmutes.rs:+11:29: +11:47 - _22 = Union32 { u32: const 0_u32 }; // scope 10 at $DIR/combine_transmutes.rs:+11:29: +11:47 - _21 = move _22 as i32 (Transmute); // scope 10 at $DIR/combine_transmutes.rs:+11:19: +11:48 - StorageDead(_22); // scope 10 at $DIR/combine_transmutes.rs:+11:47: +11:48 - StorageLive(_23); // scope 11 at $DIR/combine_transmutes.rs:+12:9: +12:11 - StorageLive(_24); // scope 11 at $DIR/combine_transmutes.rs:+12:46: +12:77 - _24 = MaybeUninit::<String>::uninit() -> [return: bb1, unwind unreachable]; // scope 11 at $DIR/combine_transmutes.rs:+12:46: +12:77 + StorageLive(_12); // scope 5 at $DIR/combine_transmutes.rs:+6:46: +6:77 + _12 = MaybeUninit::<String>::uninit() -> [return: bb1, unwind unreachable]; // scope 5 at $DIR/combine_transmutes.rs:+6:46: +6:77 // mir::Constant - // + span: $DIR/combine_transmutes.rs:46:46: 46:75 - // + user_ty: UserType(23) + // + span: $DIR/combine_transmutes.rs:40:46: 40:75 + // + user_ty: UserType(11) // + literal: Const { ty: fn() -> MaybeUninit<String> {MaybeUninit::<String>::uninit}, val: Value(<ZST>) } } bb1: { -- _23 = move _24 as std::mem::ManuallyDrop<std::string::String> (Transmute); // scope 11 at $DIR/combine_transmutes.rs:+12:36: +12:78 -+ _23 = move (_24.1: std::mem::ManuallyDrop<std::string::String>); // scope 11 at $DIR/combine_transmutes.rs:+12:36: +12:78 - StorageDead(_24); // scope 11 at $DIR/combine_transmutes.rs:+12:77: +12:78 - _0 = const (); // scope 0 at $DIR/combine_transmutes.rs:+0:32: +13:2 - StorageDead(_23); // scope 11 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_21); // scope 10 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_19); // scope 9 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_17); // scope 8 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_15); // scope 7 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_13); // scope 6 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_11); // scope 5 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_9); // scope 4 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_7); // scope 3 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_5); // scope 2 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_3); // scope 1 at $DIR/combine_transmutes.rs:+13:1: +13:2 - StorageDead(_1); // scope 0 at $DIR/combine_transmutes.rs:+13:1: +13:2 - return; // scope 0 at $DIR/combine_transmutes.rs:+13:2: +13:2 +- _11 = move _12 as std::mem::ManuallyDrop<std::string::String> (Transmute); // scope 5 at $DIR/combine_transmutes.rs:+6:36: +6:78 ++ _11 = move (_12.1: std::mem::ManuallyDrop<std::string::String>); // scope 5 at $DIR/combine_transmutes.rs:+6:36: +6:78 + StorageDead(_12); // scope 5 at $DIR/combine_transmutes.rs:+6:77: +6:78 + _0 = const (); // scope 0 at $DIR/combine_transmutes.rs:+0:32: +7:2 + StorageDead(_11); // scope 5 at $DIR/combine_transmutes.rs:+7:1: +7:2 + StorageDead(_9); // scope 4 at $DIR/combine_transmutes.rs:+7:1: +7:2 + StorageDead(_7); // scope 3 at $DIR/combine_transmutes.rs:+7:1: +7:2 + StorageDead(_5); // scope 2 at $DIR/combine_transmutes.rs:+7:1: +7:2 + StorageDead(_3); // scope 1 at $DIR/combine_transmutes.rs:+7:1: +7:2 + StorageDead(_1); // scope 0 at $DIR/combine_transmutes.rs:+7:1: +7:2 + return; // scope 0 at $DIR/combine_transmutes.rs:+7:2: +7:2 } } diff --git a/tests/mir-opt/combine_transmutes.rs b/tests/mir-opt/combine_transmutes.rs index 7088488c1b8..403f9356ce2 100644 --- a/tests/mir-opt/combine_transmutes.rs +++ b/tests/mir-opt/combine_transmutes.rs @@ -32,12 +32,6 @@ pub unsafe fn integer_transmutes() { // EMIT_MIR combine_transmutes.adt_transmutes.InstSimplify.diff pub unsafe fn adt_transmutes() { - let _a: u8 = transmute(EnumNoRepr::A); - let _a: i8 = transmute(EnumNoRepr::B); - let _a: usize = transmute(EnumReprIsize::A); - let _a: isize = transmute(EnumReprIsize::B); - let _a: u8 = transmute(std::cmp::Ordering::Less); - let _a: i8 = transmute(std::cmp::Ordering::Less); let _a: u8 = transmute(Some(std::num::NonZeroU8::MAX)); let _a: i16 = transmute(std::num::Wrapping(0_i16)); let _a: u16 = transmute(std::num::Wrapping(0_i16)); @@ -46,20 +40,4 @@ pub unsafe fn adt_transmutes() { let _a: ManuallyDrop<String> = transmute(MaybeUninit::<String>::uninit()); } -#[inline(always)] -#[custom_mir(dialect = "runtime", phase = "initial")] -const unsafe fn mir_transmute<T, U>(x: T) -> U { - mir!{ - { - RET = CastTransmute(x); - Return() - } - } -} - -pub enum EnumNoRepr { A, B, C } - -#[repr(isize)] -pub enum EnumReprIsize { A, B, C } - pub union Union32 { u32: u32, i32: i32 } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff index bc41b5d0813..5258d75bdf7 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.32bit.diff @@ -3,24 +3,20 @@ fn unreachable_box() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 - let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + let _1: std::boxed::Box<Never>; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 -- _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 -+ _2 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 +- _1 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 ++ _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + // mir::Constant + // + span: no-location + // + literal: Const { ty: Box<Never>, val: Value(Scalar(0x00000001)) } - StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff index c4376e6e17a..7e57e06a5cf 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_box.ConstProp.64bit.diff @@ -3,24 +3,20 @@ fn unreachable_box() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 - let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + let _1: std::boxed::Box<Never>; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 -- _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 -+ _2 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 +- _1 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 ++ _1 = const Box::<Never>(Unique::<Never> {{ pointer: NonNull::<Never> {{ pointer: {0x1 as *const Never} }}, _marker: PhantomData::<Never> }}, std::alloc::Global); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + // mir::Constant + // + span: no-location + // + literal: Const { ty: Box<Never>, val: Value(Scalar(0x0000000000000001)) } - StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.32bit.diff index 81b7b368993..032681f230b 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.32bit.diff @@ -3,22 +3,19 @@ fn unreachable_direct() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:39: +0:40 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:41: +3:2 - let _2: Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: (); // in scope 0 at $DIR/transmute.rs:+1:39: +1:41 - let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:15 + let _1: Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _2: (); // in scope 0 at $DIR/transmute.rs:+1:39: +1:41 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:41: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 - StorageLive(_3); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 - _3 = (); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 - _2 = move _3 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_2); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _2 = (); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _1 = move _2 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42 unreachable; // scope 2 at $DIR/transmute.rs:+1:29: +1:42 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.64bit.diff index 81b7b368993..032681f230b 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_direct.ConstProp.64bit.diff @@ -3,22 +3,19 @@ fn unreachable_direct() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:39: +0:40 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:41: +3:2 - let _2: Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: (); // in scope 0 at $DIR/transmute.rs:+1:39: +1:41 - let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:15 + let _1: Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _2: (); // in scope 0 at $DIR/transmute.rs:+1:39: +1:41 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:41: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 - StorageLive(_3); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 - _3 = (); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 - _2 = move _3 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_2); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _2 = (); // scope 2 at $DIR/transmute.rs:+1:39: +1:41 + _1 = move _2 as Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:29: +1:42 unreachable; // scope 2 at $DIR/transmute.rs:+1:29: +1:42 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.32bit.diff index 47f023cd93d..ec8a62bd62c 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.32bit.diff @@ -3,28 +3,24 @@ fn unreachable_mut() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 - let _2: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:34: +1:52 - let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + let _1: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _2: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:34: +1:52 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 -- _3 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 -+ _3 = const {0x1 as &mut Never}; // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 +- _2 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 ++ _2 = const {0x1 as &mut Never}; // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + // mir::Constant + // + span: no-location + // + literal: Const { ty: &mut Never, val: Value(Scalar(0x00000001)) } - _2 = &mut (*_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 - StorageDead(_3); // scope 0 at $DIR/transmute.rs:+1:54: +1:55 - StorageLive(_4); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + _1 = &mut (*_2); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 + StorageDead(_2); // scope 0 at $DIR/transmute.rs:+1:54: +1:55 unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.64bit.diff index 62300d2e313..288da6e56c5 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_mut.ConstProp.64bit.diff @@ -3,28 +3,24 @@ fn unreachable_mut() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 - let _2: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:34: +1:52 - let mut _4: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + let _1: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 + let mut _2: &mut Never; // in scope 0 at $DIR/transmute.rs:+1:34: +1:52 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 - StorageLive(_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 -- _3 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 -+ _3 = const {0x1 as &mut Never}; // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 + StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 +- _2 = const 1_usize as &mut Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:34: +1:52 ++ _2 = const {0x1 as &mut Never}; // scope 2 at $DIR/transmute.rs:+1:34: +1:52 + // mir::Constant + // + span: no-location + // + literal: Const { ty: &mut Never, val: Value(Scalar(0x0000000000000001)) } - _2 = &mut (*_3); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 - StorageDead(_3); // scope 0 at $DIR/transmute.rs:+1:54: +1:55 - StorageLive(_4); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 + _1 = &mut (*_2); // scope 0 at $DIR/transmute.rs:+1:34: +1:52 + StorageDead(_2); // scope 0 at $DIR/transmute.rs:+1:54: +1:55 unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.32bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.32bit.diff index 8578f898a7e..dcca0fca619 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.32bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.32bit.diff @@ -3,24 +3,20 @@ fn unreachable_ref() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 - let _2: &Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + let _1: &Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 -- _2 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48 -+ _2 = const {0x1 as &Never}; // scope 2 at $DIR/transmute.rs:+1:30: +1:48 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 +- _1 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48 ++ _1 = const {0x1 as &Never}; // scope 2 at $DIR/transmute.rs:+1:30: +1:48 + // mir::Constant + // + span: no-location + // + literal: Const { ty: &Never, val: Value(Scalar(0x00000001)) } - StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.64bit.diff b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.64bit.diff index 8b11cea9365..3a0b967e66f 100644 --- a/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.64bit.diff +++ b/tests/mir-opt/const_prop/transmute.unreachable_ref.ConstProp.64bit.diff @@ -3,24 +3,20 @@ fn unreachable_ref() -> ! { let mut _0: !; // return place in scope 0 at $DIR/transmute.rs:+0:36: +0:37 - let mut _1: !; // in scope 0 at $DIR/transmute.rs:+0:38: +3:2 - let _2: &Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/transmute.rs:+2:5: +2:16 + let _1: &Never; // in scope 0 at $DIR/transmute.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/transmute.rs:+1:9: +1:10 } scope 2 { } bb0: { - StorageLive(_1); // scope 0 at $DIR/transmute.rs:+0:38: +3:2 - StorageLive(_2); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 -- _2 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48 -+ _2 = const {0x1 as &Never}; // scope 2 at $DIR/transmute.rs:+1:30: +1:48 + StorageLive(_1); // scope 0 at $DIR/transmute.rs:+1:9: +1:10 +- _1 = const 1_usize as &Never (Transmute); // scope 2 at $DIR/transmute.rs:+1:30: +1:48 ++ _1 = const {0x1 as &Never}; // scope 2 at $DIR/transmute.rs:+1:30: +1:48 + // mir::Constant + // + span: no-location + // + literal: Const { ty: &Never, val: Value(Scalar(0x0000000000000001)) } - StorageLive(_3); // scope 1 at $DIR/transmute.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/transmute.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff b/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff index 69acebf7642..1c7b6494d6d 100644 --- a/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff +++ b/tests/mir-opt/copy-prop/copy_propagation_arg.arg_src.CopyProp.diff @@ -6,15 +6,17 @@ let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:+0:27: +0:30 let _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 scope 1 { - debug y => _2; // in scope 1 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 +- debug y => _2; // in scope 1 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 ++ debug y => _0; // in scope 1 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 } bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 - _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14 +- StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+1:9: +1:10 +- _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14 ++ _0 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:+1:13: +1:14 _1 = const 123_i32; // scope 1 at $DIR/copy_propagation_arg.rs:+2:5: +2:12 - _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:+3:5: +3:6 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+4:1: +4:2 +- _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:+3:5: +3:6 +- StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:+4:1: +4:2 return; // scope 0 at $DIR/copy_propagation_arg.rs:+4:2: +4:2 } } diff --git a/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff b/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff index 94f24b50ab7..a5129e0e8c8 100644 --- a/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff +++ b/tests/mir-opt/inline/inline_into_box_place.main.Inline.diff @@ -16,8 +16,7 @@ + let mut _4: usize; // in scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + let mut _5: usize; // in scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + let mut _6: *mut u8; // in scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL -+ let mut _7: std::boxed::Box<std::vec::Vec<u32>>; // in scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL -+ let mut _8: *const std::vec::Vec<u32>; // in scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL ++ let mut _7: *const std::vec::Vec<u32>; // in scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + scope 4 { + } + } @@ -66,12 +65,9 @@ bb3: { - StorageDead(_1); // scope 0 at $DIR/inline_into_box_place.rs:+2:1: +2:2 - return; // scope 0 at $DIR/inline_into_box_place.rs:+2:2: +2:2 -+ StorageLive(_7); // scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL -+ _7 = ShallowInitBox(move _6, std::vec::Vec<u32>); // scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL -+ _8 = (((_7.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL -+ (*_8) = move _2; // scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL -+ _1 = move _7; // scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL -+ StorageDead(_7); // scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL ++ _1 = ShallowInitBox(move _6, std::vec::Vec<u32>); // scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL ++ _7 = (((_1.0: std::ptr::Unique<std::vec::Vec<u32>>).0: std::ptr::NonNull<std::vec::Vec<u32>>).0: *const std::vec::Vec<u32>); // scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL ++ (*_7) = move _2; // scope 3 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + StorageDead(_2); // scope 0 at $DIR/inline_into_box_place.rs:+1:48: +1:49 + _0 = const (); // scope 0 at $DIR/inline_into_box_place.rs:+0:11: +2:2 + drop(_1) -> [return: bb1, unwind: bb2]; // scope 0 at $DIR/inline_into_box_place.rs:+2:1: +2:2 diff --git a/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir b/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir index 8c4ab2557a5..21570a88a6b 100644 --- a/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir +++ b/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir @@ -8,9 +8,8 @@ fn b(_1: &mut Box<T>) -> &mut T { let mut _4: &mut std::boxed::Box<T>; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15 scope 1 (inlined <Box<T> as AsMut<T>>::as_mut) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:8:7: 8:15 debug self => _4; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - let mut _5: &mut T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - let mut _6: std::boxed::Box<T>; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - let mut _7: *const T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + let mut _5: std::boxed::Box<T>; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + let mut _6: *const T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL } bb0: { @@ -18,12 +17,9 @@ fn b(_1: &mut Box<T>) -> &mut T { StorageLive(_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15 StorageLive(_4); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15 _4 = &mut (*_1); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15 - StorageLive(_5); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:7: +1:15 - _6 = deref_copy (*_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _7 = (((_6.0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>).0: *const T); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _5 = &mut (*_7); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _3 = _5; // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - StorageDead(_5); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:7: +1:15 + _5 = deref_copy (*_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _6 = (((_5.0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>).0: *const T); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _3 = &mut (*_6); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _2 = &mut (*_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15 StorageDead(_4); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:14: +1:15 _0 = &mut (*_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15 diff --git a/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir b/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir index b18a41b622e..4f9342247d7 100644 --- a/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir +++ b/tests/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir @@ -7,21 +7,17 @@ fn d(_1: &Box<T>) -> &T { let mut _3: &std::boxed::Box<T>; // in scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15 scope 1 (inlined <Box<T> as AsRef<T>>::as_ref) { // at $DIR/issue_58867_inline_as_ref_as_mut.rs:18:7: 18:15 debug self => _3; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - let _4: &T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - let mut _5: std::boxed::Box<T>; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - let mut _6: *const T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + let mut _4: std::boxed::Box<T>; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + let mut _5: *const T; // in scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL } bb0: { StorageLive(_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15 StorageLive(_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15 _3 = &(*_1); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15 - StorageLive(_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _5 = deref_copy (*_3); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _6 = (((_5.0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>).0: *const T); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _4 = &(*_6); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - _2 = _4; // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL - StorageDead(_4); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _4 = deref_copy (*_3); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _5 = (((_4.0: std::ptr::Unique<T>).0: std::ptr::NonNull<T>).0: *const T); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL + _2 = &(*_5); // scope 1 at $SRC_DIR/alloc/src/boxed.rs:LL:COL _0 = &(*_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:5: +1:15 StorageDead(_3); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+1:14: +1:15 StorageDead(_2); // scope 0 at $DIR/issue_58867_inline_as_ref_as_mut.rs:+2:1: +2:2 diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff index 473e02f1cb1..d76cd0e2bb8 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.Inline.diff @@ -12,7 +12,51 @@ + debug rhs => _4; // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + let mut _5: u16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _6: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ let mut _7: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + scope 2 { ++ scope 3 (inlined core::num::<impl u16>::unchecked_shl::conv) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ debug x => _7; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ let mut _8: std::option::Option<u16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ let mut _9: std::result::Result<u16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ scope 4 { ++ scope 5 (inlined <u32 as TryInto<u16>>::try_into) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ debug self => _7; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL ++ scope 6 (inlined convert::num::<impl TryFrom<u32> for u16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL ++ debug u => _7; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ let mut _10: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ let mut _11: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ let mut _12: u16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ } ++ } ++ scope 7 (inlined Result::<u16, TryFromIntError>::ok) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ debug self => _9; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ let mut _13: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ let _14: u16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ scope 8 { ++ debug x => _14; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL ++ } ++ } ++ scope 9 (inlined #[track_caller] Option::<u16>::unwrap_unchecked) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ debug self => _8; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL ++ let mut _15: &std::option::Option<u16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL ++ let mut _16: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL ++ scope 10 { ++ debug val => _5; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL ++ } ++ scope 11 { ++ scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL ++ scope 14 { ++ scope 15 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL ++ } ++ } ++ } ++ } ++ scope 12 (inlined Option::<u16>::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL ++ debug self => _15; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL ++ } ++ } ++ } ++ } + } + } @@ -22,30 +66,87 @@ StorageLive(_4); // scope 0 at $DIR/unchecked_shifts.rs:+1:21: +1:22 _4 = _2; // scope 0 at $DIR/unchecked_shifts.rs:+1:21: +1:22 - _0 = core::num::<impl u16>::unchecked_shl(move _3, move _4) -> bb1; // scope 0 at $DIR/unchecked_shifts.rs:+1:5: +1:23 +- // mir::Constant +- // + span: $DIR/unchecked_shifts.rs:11:7: 11:20 +- // + literal: Const { ty: unsafe fn(u16, u32) -> u16 {core::num::<impl u16>::unchecked_shl}, val: Value(<ZST>) } + StorageLive(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_6); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _6 = (_4,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL -+ _5 = core::num::<impl u16>::unchecked_shl::conv(move (_6.0: u32)) -> bb1; // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - // mir::Constant -- // + span: $DIR/unchecked_shifts.rs:11:7: 11:20 -- // + literal: Const { ty: unsafe fn(u16, u32) -> u16 {core::num::<impl u16>::unchecked_shl}, val: Value(<ZST>) } -+ // + span: $SRC_DIR/core/src/num/mod.rs:LL:COL -+ // + literal: Const { ty: fn(u32) -> u16 {core::num::<impl u16>::unchecked_shl::conv}, val: Value(<ZST>) } ++ StorageLive(_7); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ _7 = move (_6.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageLive(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageLive(_9); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageLive(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ StorageLive(_11); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ _11 = const 65535_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ _10 = Gt(_7, move _11); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ StorageDead(_11); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ switchInt(move _10) -> [0: bb3, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb1: { -+ StorageDead(_6); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL -+ _0 = unchecked_shl::<u16>(_3, move _5) -> [return: bb2, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL -+ // mir::Constant -+ // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL -+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u16, u16) -> u16 {unchecked_shl::<u16>}, val: Value(<ZST>) } -+ } -+ -+ bb2: { + StorageDead(_5); // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL StorageDead(_4); // scope 0 at $DIR/unchecked_shifts.rs:+1:22: +1:23 StorageDead(_3); // scope 0 at $DIR/unchecked_shifts.rs:+1:22: +1:23 return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 ++ } ++ ++ bb2: { ++ _9 = Result::<u16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ // mir::Constant ++ // + span: no-location ++ // + literal: Const { ty: TryFromIntError, val: Value(<ZST>) } ++ goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ } ++ ++ bb3: { ++ StorageLive(_12); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ _12 = _7 as u16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ _9 = Result::<u16, TryFromIntError>::Ok(move _12); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ StorageDead(_12); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ } ++ ++ bb4: { ++ StorageDead(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ StorageLive(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ _13 = discriminant(_9); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ switchInt(move _13) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ } ++ ++ bb5: { ++ _8 = Option::<u16>::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ } ++ ++ bb6: { ++ unreachable; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ } ++ ++ bb7: { ++ _14 = move ((_9 as Ok).0: u16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ _8 = Option::<u16>::Some(move _14); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL ++ goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ } ++ ++ bb8: { ++ StorageDead(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageDead(_9); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageLive(_15); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ _16 = discriminant(_8); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL ++ switchInt(move _16) -> [1: bb9, otherwise: bb6]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL ++ } ++ ++ bb9: { ++ _5 = move ((_8 as Some).0: u16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL ++ StorageDead(_15); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageDead(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageDead(_7); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageDead(_6); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ _0 = unchecked_shl::<u16>(_3, move _5) -> [return: bb1, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL ++ // mir::Constant ++ // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL ++ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u16, u16) -> u16 {unchecked_shl::<u16>}, val: Value(<ZST>) } } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir index 9b7b11ef659..3c175ed1504 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shl_unsigned_smaller.PreCodegen.after.mir @@ -9,7 +9,51 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { debug rhs => _2; // in scope 1 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL let mut _3: u16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL let mut _4: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _5: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL scope 2 { + scope 3 (inlined core::num::<impl u16>::unchecked_shl::conv) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL + debug x => _5; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _6: std::option::Option<u16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _7: std::result::Result<u16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + scope 4 { + scope 5 (inlined <u32 as TryInto<u16>>::try_into) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL + debug self => _5; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + scope 6 (inlined convert::num::<impl TryFrom<u32> for u16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL + debug u => _5; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _8: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _9: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _10: u16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + } + } + scope 7 (inlined Result::<u16, TryFromIntError>::ok) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL + debug self => _7; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + let mut _11: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + let _12: u16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + scope 8 { + debug x => _12; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + } + } + scope 9 (inlined #[track_caller] Option::<u16>::unwrap_unchecked) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL + debug self => _6; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _13: &std::option::Option<u16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _14: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + scope 10 { + debug val => _3; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL + } + scope 11 { + scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL + scope 14 { + scope 15 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + } + } + } + scope 12 (inlined Option::<u16>::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _13; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL + } + } + } + } } } @@ -17,22 +61,78 @@ fn unchecked_shl_unsigned_smaller(_1: u16, _2: u32) -> u16 { StorageLive(_3); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL StorageLive(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL _4 = (_2,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _3 = core::num::<impl u16>::unchecked_shl::conv(move (_4.0: u32)) -> bb1; // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/num/mod.rs:LL:COL - // + literal: Const { ty: fn(u32) -> u16 {core::num::<impl u16>::unchecked_shl::conv}, val: Value(<ZST>) } + StorageLive(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _5 = move (_4.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageLive(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _9 = const 65535_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _8 = Gt(_5, move _9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + switchInt(move _8) -> [0: bb3, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb1: { + StorageDead(_3); // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 + } + + bb2: { + _7 = Result::<u16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + // mir::Constant + // + span: no-location + // + literal: Const { ty: TryFromIntError, val: Value(<ZST>) } + goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + } + + bb3: { + StorageLive(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _10 = _5 as u16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _7 = Result::<u16, TryFromIntError>::Ok(move _10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + } + + bb4: { + StorageDead(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageLive(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _11 = discriminant(_7); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + switchInt(move _11) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + } + + bb5: { + _6 = Option::<u16>::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + } + + bb6: { + unreachable; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + } + + bb7: { + _12 = move ((_7 as Ok).0: u16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _6 = Option::<u16>::Some(move _12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + } + + bb8: { + StorageDead(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _14 = discriminant(_6); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _14) -> [1: bb9, otherwise: bb6]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + } + + bb9: { + _3 = move ((_6 as Some).0: u16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL StorageDead(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _0 = unchecked_shl::<u16>(_1, move _3) -> [return: bb2, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL + _0 = unchecked_shl::<u16>(_1, move _3) -> [return: bb1, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/num/uint_macros.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u16, u16) -> u16 {unchecked_shl::<u16>}, val: Value(<ZST>) } } - - bb2: { - StorageDead(_3); // scope 2 at $SRC_DIR/core/src/num/uint_macros.rs:LL:COL - return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 - } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.diff b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.diff index 9638ddda46b..f3d3e6090bb 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.diff +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.Inline.diff @@ -12,7 +12,51 @@ + debug rhs => _4; // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL + let mut _5: i16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _6: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ let mut _7: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + scope 2 { ++ scope 3 (inlined core::num::<impl i16>::unchecked_shr::conv) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ debug x => _7; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ let mut _8: std::option::Option<i16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ let mut _9: std::result::Result<i16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ scope 4 { ++ scope 5 (inlined <u32 as TryInto<i16>>::try_into) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ debug self => _7; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL ++ scope 6 (inlined convert::num::<impl TryFrom<u32> for i16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL ++ debug u => _7; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ let mut _10: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ let mut _11: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ let mut _12: i16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ } ++ } ++ scope 7 (inlined Result::<i16, TryFromIntError>::ok) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ debug self => _9; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ let mut _13: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ let _14: i16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ scope 8 { ++ debug x => _14; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL ++ } ++ } ++ scope 9 (inlined #[track_caller] Option::<i16>::unwrap_unchecked) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ debug self => _8; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL ++ let mut _15: &std::option::Option<i16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL ++ let mut _16: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL ++ scope 10 { ++ debug val => _5; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL ++ } ++ scope 11 { ++ scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL ++ scope 14 { ++ scope 15 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL ++ } ++ } ++ } ++ } ++ scope 12 (inlined Option::<i16>::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL ++ debug self => _15; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL ++ } ++ } ++ } ++ } + } + } @@ -22,30 +66,87 @@ StorageLive(_4); // scope 0 at $DIR/unchecked_shifts.rs:+1:21: +1:22 _4 = _2; // scope 0 at $DIR/unchecked_shifts.rs:+1:21: +1:22 - _0 = core::num::<impl i16>::unchecked_shr(move _3, move _4) -> bb1; // scope 0 at $DIR/unchecked_shifts.rs:+1:5: +1:23 +- // mir::Constant +- // + span: $DIR/unchecked_shifts.rs:17:7: 17:20 +- // + literal: Const { ty: unsafe fn(i16, u32) -> i16 {core::num::<impl i16>::unchecked_shr}, val: Value(<ZST>) } + StorageLive(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_6); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _6 = (_4,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL -+ _5 = core::num::<impl i16>::unchecked_shr::conv(move (_6.0: u32)) -> bb1; // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - // mir::Constant -- // + span: $DIR/unchecked_shifts.rs:17:7: 17:20 -- // + literal: Const { ty: unsafe fn(i16, u32) -> i16 {core::num::<impl i16>::unchecked_shr}, val: Value(<ZST>) } -+ // + span: $SRC_DIR/core/src/num/mod.rs:LL:COL -+ // + literal: Const { ty: fn(u32) -> i16 {core::num::<impl i16>::unchecked_shr::conv}, val: Value(<ZST>) } ++ StorageLive(_7); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ _7 = move (_6.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageLive(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageLive(_9); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageLive(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ StorageLive(_11); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ _11 = const 32767_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ _10 = Gt(_7, move _11); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ StorageDead(_11); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ switchInt(move _10) -> [0: bb3, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb1: { -+ StorageDead(_6); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL -+ _0 = unchecked_shr::<i16>(_3, move _5) -> [return: bb2, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL -+ // mir::Constant -+ // + span: $SRC_DIR/core/src/num/int_macros.rs:LL:COL -+ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i16, i16) -> i16 {unchecked_shr::<i16>}, val: Value(<ZST>) } -+ } -+ -+ bb2: { + StorageDead(_5); // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL StorageDead(_4); // scope 0 at $DIR/unchecked_shifts.rs:+1:22: +1:23 StorageDead(_3); // scope 0 at $DIR/unchecked_shifts.rs:+1:22: +1:23 return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 ++ } ++ ++ bb2: { ++ _9 = Result::<i16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ // mir::Constant ++ // + span: no-location ++ // + literal: Const { ty: TryFromIntError, val: Value(<ZST>) } ++ goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ } ++ ++ bb3: { ++ StorageLive(_12); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ _12 = _7 as i16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ _9 = Result::<i16, TryFromIntError>::Ok(move _12); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ StorageDead(_12); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ } ++ ++ bb4: { ++ StorageDead(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL ++ StorageLive(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ _13 = discriminant(_9); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ switchInt(move _13) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ } ++ ++ bb5: { ++ _8 = Option::<i16>::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ } ++ ++ bb6: { ++ unreachable; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ } ++ ++ bb7: { ++ _14 = move ((_9 as Ok).0: i16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ _8 = Option::<i16>::Some(move _14); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL ++ goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL ++ } ++ ++ bb8: { ++ StorageDead(_14); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageDead(_9); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageLive(_15); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ _16 = discriminant(_8); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL ++ switchInt(move _16) -> [1: bb9, otherwise: bb6]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL ++ } ++ ++ bb9: { ++ _5 = move ((_8 as Some).0: i16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL ++ StorageDead(_15); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageDead(_8); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageDead(_7); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ StorageDead(_6); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL ++ _0 = unchecked_shr::<i16>(_3, move _5) -> [return: bb1, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL ++ // mir::Constant ++ // + span: $SRC_DIR/core/src/num/int_macros.rs:LL:COL ++ // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i16, i16) -> i16 {unchecked_shr::<i16>}, val: Value(<ZST>) } } } diff --git a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir index afe6d08741b..724b3c56723 100644 --- a/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir +++ b/tests/mir-opt/inline/unchecked_shifts.unchecked_shr_signed_smaller.PreCodegen.after.mir @@ -9,7 +9,51 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 { debug rhs => _2; // in scope 1 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL let mut _3: i16; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL let mut _4: (u32,); // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _5: u32; // in scope 1 at $SRC_DIR/core/src/num/mod.rs:LL:COL scope 2 { + scope 3 (inlined core::num::<impl i16>::unchecked_shr::conv) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL + debug x => _5; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _6: std::option::Option<i16>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + let mut _7: std::result::Result<i16, std::num::TryFromIntError>; // in scope 3 at $SRC_DIR/core/src/num/mod.rs:LL:COL + scope 4 { + scope 5 (inlined <u32 as TryInto<i16>>::try_into) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL + debug self => _5; // in scope 5 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + scope 6 (inlined convert::num::<impl TryFrom<u32> for i16>::try_from) { // at $SRC_DIR/core/src/convert/mod.rs:LL:COL + debug u => _5; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _8: bool; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _9: u32; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + let mut _10: i16; // in scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + } + } + scope 7 (inlined Result::<i16, TryFromIntError>::ok) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL + debug self => _7; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + let mut _11: isize; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + let _12: i16; // in scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + scope 8 { + debug x => _12; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + } + } + scope 9 (inlined #[track_caller] Option::<i16>::unwrap_unchecked) { // at $SRC_DIR/core/src/num/mod.rs:LL:COL + debug self => _6; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _13: &std::option::Option<i16>; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _14: isize; // in scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + scope 10 { + debug val => _3; // in scope 10 at $SRC_DIR/core/src/option.rs:LL:COL + } + scope 11 { + scope 13 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL + scope 14 { + scope 15 (inlined unreachable_unchecked::runtime) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL + } + } + } + } + scope 12 (inlined Option::<i16>::is_some) { // at $SRC_DIR/core/src/option.rs:LL:COL + debug self => _13; // in scope 12 at $SRC_DIR/core/src/option.rs:LL:COL + } + } + } + } } } @@ -17,22 +61,78 @@ fn unchecked_shr_signed_smaller(_1: i16, _2: u32) -> i16 { StorageLive(_3); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL StorageLive(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL _4 = (_2,); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _3 = core::num::<impl i16>::unchecked_shr::conv(move (_4.0: u32)) -> bb1; // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/num/mod.rs:LL:COL - // + literal: Const { ty: fn(u32) -> i16 {core::num::<impl i16>::unchecked_shr::conv}, val: Value(<ZST>) } + StorageLive(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _5 = move (_4.0: u32); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageLive(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _9 = const 32767_u32; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _8 = Gt(_5, move _9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_9); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + switchInt(move _8) -> [0: bb3, otherwise: bb2]; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL } bb1: { + StorageDead(_3); // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL + return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 + } + + bb2: { + _7 = Result::<i16, TryFromIntError>::Err(const TryFromIntError(())); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + // mir::Constant + // + span: no-location + // + literal: Const { ty: TryFromIntError, val: Value(<ZST>) } + goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + } + + bb3: { + StorageLive(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _10 = _5 as i16 (IntToInt); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + _7 = Result::<i16, TryFromIntError>::Ok(move _10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageDead(_10); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + goto -> bb4; // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + } + + bb4: { + StorageDead(_8); // scope 6 at $SRC_DIR/core/src/convert/num.rs:LL:COL + StorageLive(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _11 = discriminant(_7); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + switchInt(move _11) -> [0: bb7, 1: bb5, otherwise: bb6]; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + } + + bb5: { + _6 = Option::<i16>::None; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + } + + bb6: { + unreachable; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + } + + bb7: { + _12 = move ((_7 as Ok).0: i16); // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + _6 = Option::<i16>::Some(move _12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + goto -> bb8; // scope 7 at $SRC_DIR/core/src/result.rs:LL:COL + } + + bb8: { + StorageDead(_12); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_7); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageLive(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + _14 = discriminant(_6); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + switchInt(move _14) -> [1: bb9, otherwise: bb6]; // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + } + + bb9: { + _3 = move ((_6 as Some).0: i16); // scope 9 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_13); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_6); // scope 4 at $SRC_DIR/core/src/num/mod.rs:LL:COL + StorageDead(_5); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL StorageDead(_4); // scope 2 at $SRC_DIR/core/src/num/mod.rs:LL:COL - _0 = unchecked_shr::<i16>(_1, move _3) -> [return: bb2, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL + _0 = unchecked_shr::<i16>(_1, move _3) -> [return: bb1, unwind unreachable]; // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/num/int_macros.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(i16, i16) -> i16 {unchecked_shr::<i16>}, val: Value(<ZST>) } } - - bb2: { - StorageDead(_3); // scope 2 at $SRC_DIR/core/src/num/int_macros.rs:LL:COL - return; // scope 0 at $DIR/unchecked_shifts.rs:+2:2: +2:2 - } } diff --git a/tests/mir-opt/inline/unsized_argument.caller.Inline.diff b/tests/mir-opt/inline/unsized_argument.caller.Inline.diff new file mode 100644 index 00000000000..745f2bb193a --- /dev/null +++ b/tests/mir-opt/inline/unsized_argument.caller.Inline.diff @@ -0,0 +1,50 @@ +- // MIR for `caller` before Inline ++ // MIR for `caller` after Inline + + fn caller(_1: Box<[i32]>) -> () { + debug x => _1; // in scope 0 at $DIR/unsized_argument.rs:+0:11: +0:12 + let mut _0: (); // return place in scope 0 at $DIR/unsized_argument.rs:+0:26: +0:26 + let _2: (); // in scope 0 at $DIR/unsized_argument.rs:+1:5: +1:15 + let mut _3: std::boxed::Box<[i32]>; // in scope 0 at $DIR/unsized_argument.rs:+1:13: +1:14 + let mut _4: (); // in scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15 + let mut _5: (); // in scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15 + let mut _6: (); // in scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15 + let mut _7: *const [i32]; // in scope 0 at $DIR/unsized_argument.rs:+1:13: +1:14 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/unsized_argument.rs:+1:5: +1:15 + StorageLive(_3); // scope 0 at $DIR/unsized_argument.rs:+1:13: +1:14 + _3 = move _1; // scope 0 at $DIR/unsized_argument.rs:+1:13: +1:14 + _7 = (((_3.0: std::ptr::Unique<[i32]>).0: std::ptr::NonNull<[i32]>).0: *const [i32]); // scope 0 at $DIR/unsized_argument.rs:+1:5: +1:15 + _2 = callee(move (*_7)) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/unsized_argument.rs:+1:5: +1:15 + // mir::Constant + // + span: $DIR/unsized_argument.rs:9:5: 9:11 + // + literal: Const { ty: fn([i32]) {callee}, val: Value(<ZST>) } + } + + bb1: { + StorageDead(_3); // scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15 + StorageDead(_2); // scope 0 at $DIR/unsized_argument.rs:+1:15: +1:16 + _0 = const (); // scope 0 at $DIR/unsized_argument.rs:+0:26: +2:2 + return; // scope 0 at $DIR/unsized_argument.rs:+2:2: +2:2 + } + + bb2 (cleanup): { + resume; // scope 0 at $DIR/unsized_argument.rs:+0:1: +2:2 + } + + bb3: { + _4 = alloc::alloc::box_free::<[i32], std::alloc::Global>(move (_3.0: std::ptr::Unique<[i32]>), move (_3.1: std::alloc::Global)) -> bb1; // scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15 + // mir::Constant + // + span: $DIR/unsized_argument.rs:9:14: 9:15 + // + literal: Const { ty: unsafe fn(Unique<[i32]>, std::alloc::Global) {alloc::alloc::box_free::<[i32], std::alloc::Global>}, val: Value(<ZST>) } + } + + bb4 (cleanup): { + _6 = alloc::alloc::box_free::<[i32], std::alloc::Global>(move (_3.0: std::ptr::Unique<[i32]>), move (_3.1: std::alloc::Global)) -> [return: bb2, unwind terminate]; // scope 0 at $DIR/unsized_argument.rs:+1:14: +1:15 + // mir::Constant + // + span: $DIR/unsized_argument.rs:9:14: 9:15 + // + literal: Const { ty: unsafe fn(Unique<[i32]>, std::alloc::Global) {alloc::alloc::box_free::<[i32], std::alloc::Global>}, val: Value(<ZST>) } + } + } + diff --git a/tests/mir-opt/inline/unsized_argument.rs b/tests/mir-opt/inline/unsized_argument.rs new file mode 100644 index 00000000000..b2c51407fd5 --- /dev/null +++ b/tests/mir-opt/inline/unsized_argument.rs @@ -0,0 +1,15 @@ +// needs-unwind +#![feature(unsized_fn_params)] + +#[inline(always)] +fn callee(y: [i32]) {} + +// EMIT_MIR unsized_argument.caller.Inline.diff +fn caller(x: Box<[i32]>) { + callee(*x); +} + +fn main() { + let b = Box::new([1]); + caller(b); +} diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.diff b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.diff index 778ecc46d73..8a8cd896e85 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.diff +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.Inline.diff @@ -9,9 +9,8 @@ + debug self => _2; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _3: &std::option::Option<T>; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + let mut _4: isize; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL -+ let _5: T; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + scope 2 { -+ debug val => _5; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL ++ debug val => _0; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL + } + scope 3 { + scope 5 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL @@ -47,10 +46,7 @@ - bb2 (cleanup): { - resume; // scope 0 at $DIR/unwrap_unchecked.rs:+0:1: +2:2 + bb2: { -+ StorageLive(_5); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL -+ _5 = move ((_2 as Some).0: T); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL -+ _0 = move _5; // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL -+ StorageDead(_5); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL ++ _0 = move ((_2 as Some).0: T); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + StorageDead(_3); // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27 + StorageDead(_2); // scope 0 at $DIR/unwrap_unchecked.rs:+1:26: +1:27 + return; // scope 0 at $DIR/unwrap_unchecked.rs:+2:2: +2:2 diff --git a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir index 5cdf4fa46e3..c5e2469fc27 100644 --- a/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir +++ b/tests/mir-opt/inline/unwrap_unchecked.unwrap_unchecked.PreCodegen.after.mir @@ -7,9 +7,8 @@ fn unwrap_unchecked(_1: Option<T>) -> T { debug self => _1; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL let mut _2: &std::option::Option<T>; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL let mut _3: isize; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL - let _4: T; // in scope 1 at $SRC_DIR/core/src/option.rs:LL:COL scope 2 { - debug val => _4; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL + debug val => _0; // in scope 2 at $SRC_DIR/core/src/option.rs:LL:COL } scope 3 { scope 5 (inlined unreachable_unchecked) { // at $SRC_DIR/core/src/option.rs:LL:COL @@ -35,10 +34,7 @@ fn unwrap_unchecked(_1: Option<T>) -> T { } bb2: { - StorageLive(_4); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL - _4 = move ((_1 as Some).0: T); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL - _0 = move _4; // scope 2 at $SRC_DIR/core/src/option.rs:LL:COL - StorageDead(_4); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL + _0 = move ((_1 as Some).0: T); // scope 1 at $SRC_DIR/core/src/option.rs:LL:COL StorageDead(_2); // scope 0 at $DIR/unwrap_unchecked.rs:+1:9: +1:27 return; // scope 0 at $DIR/unwrap_unchecked.rs:+2:2: +2:2 } diff --git a/tests/mir-opt/issue_72181_1.f.built.after.mir b/tests/mir-opt/issue_72181_1.f.built.after.mir index 4086da52011..25f47225113 100644 --- a/tests/mir-opt/issue_72181_1.f.built.after.mir +++ b/tests/mir-opt/issue_72181_1.f.built.after.mir @@ -3,27 +3,13 @@ fn f(_1: Void) -> ! { debug v => _1; // in scope 0 at $DIR/issue_72181_1.rs:+0:6: +0:7 let mut _0: !; // return place in scope 0 at $DIR/issue_72181_1.rs:+0:18: +0:19 - let mut _2: !; // in scope 0 at $DIR/issue_72181_1.rs:+0:20: +2:2 - let mut _3: !; // in scope 0 at $DIR/issue_72181_1.rs:+1:5: +1:15 bb0: { - StorageLive(_2); // scope 0 at $DIR/issue_72181_1.rs:+0:20: +2:2 - StorageLive(_3); // scope 0 at $DIR/issue_72181_1.rs:+1:5: +1:15 FakeRead(ForMatchedPlace(None), _1); // scope 0 at $DIR/issue_72181_1.rs:+1:11: +1:12 unreachable; // scope 0 at $DIR/issue_72181_1.rs:+1:11: +1:12 } bb1: { - unreachable; // scope 0 at $DIR/issue_72181_1.rs:+1:5: +1:15 - } - - bb2: { - StorageDead(_3); // scope 0 at $DIR/issue_72181_1.rs:+1:14: +1:15 - unreachable; // scope 0 at $DIR/issue_72181_1.rs:+0:20: +2:2 - } - - bb3: { - StorageDead(_2); // scope 0 at $DIR/issue_72181_1.rs:+2:1: +2:2 return; // scope 0 at $DIR/issue_72181_1.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff index abb89b91dd3..73b9ea46c44 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff @@ -21,9 +21,9 @@ let _13: &T; // in scope 1 at $DIR/issue_76432.rs:+3:18: +3:24 let _14: &T; // in scope 1 at $DIR/issue_76432.rs:+3:26: +3:32 scope 2 { - debug v1 => _12; // in scope 2 at $DIR/issue_76432.rs:+3:10: +3:16 - debug v2 => _13; // in scope 2 at $DIR/issue_76432.rs:+3:18: +3:24 - debug v3 => _14; // in scope 2 at $DIR/issue_76432.rs:+3:26: +3:32 + debug v1 => &(*_2)[0 of 3]; // in scope 2 at $DIR/issue_76432.rs:+3:10: +3:16 + debug v2 => &(*_2)[1 of 3]; // in scope 2 at $DIR/issue_76432.rs:+3:18: +3:24 + debug v3 => &(*_2)[2 of 3]; // in scope 2 at $DIR/issue_76432.rs:+3:26: +3:32 } } @@ -52,15 +52,6 @@ } bb2: { - StorageLive(_12); // scope 1 at $DIR/issue_76432.rs:+3:10: +3:16 - _12 = &(*_2)[0 of 3]; // scope 1 at $DIR/issue_76432.rs:+3:10: +3:16 - StorageLive(_13); // scope 1 at $DIR/issue_76432.rs:+3:18: +3:24 - _13 = &(*_2)[1 of 3]; // scope 1 at $DIR/issue_76432.rs:+3:18: +3:24 - StorageLive(_14); // scope 1 at $DIR/issue_76432.rs:+3:26: +3:32 - _14 = &(*_2)[2 of 3]; // scope 1 at $DIR/issue_76432.rs:+3:26: +3:32 - StorageDead(_14); // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85 - StorageDead(_13); // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85 - StorageDead(_12); // scope 1 at $DIR/issue_76432.rs:+3:84: +3:85 StorageDead(_5); // scope 0 at $DIR/issue_76432.rs:+6:1: +6:2 StorageDead(_2); // scope 0 at $DIR/issue_76432.rs:+6:1: +6:2 return; // scope 0 at $DIR/issue_76432.rs:+6:2: +6:2 diff --git a/tests/mir-opt/issue_99325.main.built.after.mir b/tests/mir-opt/issue_99325.main.built.after.mir index f0c9ef419bd..0424ce3abeb 100644 --- a/tests/mir-opt/issue_99325.main.built.after.mir +++ b/tests/mir-opt/issue_99325.main.built.after.mir @@ -1,8 +1,8 @@ // MIR for `main` after built | User Type Annotations -| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Value(Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)])) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} -| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Unevaluated(UnevaluatedConst { def: DefId(0:8 ~ issue_99325[22bb]::main::{constant#1}), substs: [] }) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 0: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Branch([Leaf(0x41), Leaf(0x41), Leaf(0x41), Leaf(0x41)]) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:10:16: 10:46, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} +| 1: user_ty: Canonical { value: TypeOf(DefId(0:3 ~ issue_99325[22bb]::function_with_bytes), UserSubsts { substs: [Const { ty: &'static [u8; 4], kind: Unevaluated([], DefId(0:8 ~ issue_99325[22bb]::main::{constant#1})) }], user_self_ty: None }), max_universe: U0, variables: [] }, span: $DIR/issue_99325.rs:11:16: 11:68, inferred_ty: fn() -> &'static [u8] {function_with_bytes::<&*b"AAAA">} | fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/issue_99325.rs:+0:15: +0:15 diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff index 8735a750060..aa5d9619d10 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_box_uninhabited.LowerIntrinsics.diff @@ -3,26 +3,22 @@ fn transmute_to_box_uninhabited() -> ! { let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 - let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 - let _2: std::boxed::Box<Never>; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + let _1: std::boxed::Box<Never>; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 -- _2 = transmute::<usize, Box<Never>>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _1 = transmute::<usize, Box<Never>>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:70:25: 70:44 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> Box<Never> {transmute::<usize, Box<Never>>}, val: Value(<ZST>) } -+ _2 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 ++ _1 = const 1_usize as std::boxed::Box<Never> (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 } bb1: { - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff index a772132770c..5fafd45fe85 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_mut_uninhabited.LowerIntrinsics.diff @@ -3,26 +3,22 @@ fn transmute_to_mut_uninhabited() -> ! { let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 - let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 - let _2: &mut Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + let _1: &mut Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 -- _2 = transmute::<usize, &mut Never>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _1 = transmute::<usize, &mut Never>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:64:25: 64:44 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &mut Never {transmute::<usize, &mut Never>}, val: Value(<ZST>) } -+ _2 = const 1_usize as &mut Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 ++ _1 = const 1_usize as &mut Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:25: +1:52 } bb1: { - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff index c4d53d4e8c7..08dead13211 100644 --- a/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.transmute_to_ref_uninhabited.LowerIntrinsics.diff @@ -3,26 +3,22 @@ fn transmute_to_ref_uninhabited() -> ! { let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:49: +0:50 - let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 - let _2: &Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 - let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+2:5: +2:16 + let _1: &Never; // in scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 scope 1 { - debug x => _2; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 + debug x => _1; // in scope 1 at $DIR/lower_intrinsics.rs:+1:9: +1:10 } bb0: { - StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+0:51: +3:2 - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 -- _2 = transmute::<usize, &Never>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:9: +1:10 +- _1 = transmute::<usize, &Never>(const 1_usize) -> [return: bb1, unwind unreachable]; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:58:21: 58:40 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize) -> &Never {transmute::<usize, &Never>}, val: Value(<ZST>) } -+ _2 = const 1_usize as &Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 ++ _1 = const 1_usize as &Never (Transmute); // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 + goto -> bb1; // scope 0 at $DIR/lower_intrinsics.rs:+1:21: +1:48 } bb1: { - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+2:5: +2:16 unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+2:11: +2:13 } } diff --git a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff index c0cc698c481..28e45909c33 100644 --- a/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff +++ b/tests/mir-opt/lower_intrinsics.unreachable.LowerIntrinsics.diff @@ -3,16 +3,15 @@ fn unreachable() -> ! { let mut _0: !; // return place in scope 0 at $DIR/lower_intrinsics.rs:+0:25: +0:26 - let mut _1: !; // in scope 0 at $DIR/lower_intrinsics.rs:+0:27: +2:2 - let _2: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:45 - let mut _3: !; // in scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:45 + let _1: (); // in scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:45 + let mut _2: !; // in scope 0 at $DIR/lower_intrinsics.rs:+1:14: +1:45 scope 1 { } bb0: { - StorageLive(_2); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:47 - StorageLive(_3); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 -- _3 = std::intrinsics::unreachable() -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 + StorageLive(_1); // scope 0 at $DIR/lower_intrinsics.rs:+1:5: +1:47 + StorageLive(_2); // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 +- _2 = std::intrinsics::unreachable() -> unwind unreachable; // scope 1 at $DIR/lower_intrinsics.rs:+1:14: +1:45 - // mir::Constant - // + span: $DIR/lower_intrinsics.rs:31:14: 31:43 - // + literal: Const { ty: unsafe extern "rust-intrinsic" fn() -> ! {std::intrinsics::unreachable}, val: Value(<ZST>) } diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index 71bdfcc5c49..c425f3cd506 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -22,7 +22,7 @@ | fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/region_subtyping_basic.rs:+0:11: +0:11 - let mut _1: [usize; Const(Value(Leaf(0x00000003)): usize)]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14 + let mut _1: [usize; Const { ty: usize, kind: Leaf(0x00000003) }]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14 let _3: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:16: +2:17 let mut _4: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18 let mut _5: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18 diff --git a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 9fa8609b751..22ad24f8d77 100644 --- a/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir +++ b/tests/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -22,7 +22,7 @@ | fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/region_subtyping_basic.rs:+0:11: +0:11 - let mut _1: [usize; Const(Value(Leaf(0x0000000000000003)): usize)]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14 + let mut _1: [usize; Const { ty: usize, kind: Leaf(0x0000000000000003) }]; // in scope 0 at $DIR/region_subtyping_basic.rs:+1:9: +1:14 let _3: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:16: +2:17 let mut _4: usize; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18 let mut _5: bool; // in scope 0 at $DIR/region_subtyping_basic.rs:+2:14: +2:18 diff --git a/tests/mir-opt/pre-codegen/mem_replace.manual_replace.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/mem_replace.manual_replace.PreCodegen.after.mir index 4fddd50702c..1d23871029d 100644 --- a/tests/mir-opt/pre-codegen/mem_replace.manual_replace.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/mem_replace.manual_replace.PreCodegen.after.mir @@ -4,17 +4,13 @@ fn manual_replace(_1: &mut u32, _2: u32) -> u32 { debug r => _1; // in scope 0 at $DIR/mem_replace.rs:+0:23: +0:24 debug v => _2; // in scope 0 at $DIR/mem_replace.rs:+0:36: +0:37 let mut _0: u32; // return place in scope 0 at $DIR/mem_replace.rs:+0:47: +0:50 - let _3: u32; // in scope 0 at $DIR/mem_replace.rs:+1:9: +1:13 scope 1 { - debug temp => _3; // in scope 1 at $DIR/mem_replace.rs:+1:9: +1:13 + debug temp => _0; // in scope 1 at $DIR/mem_replace.rs:+1:9: +1:13 } bb0: { - StorageLive(_3); // scope 0 at $DIR/mem_replace.rs:+1:9: +1:13 - _3 = (*_1); // scope 0 at $DIR/mem_replace.rs:+1:16: +1:18 + _0 = (*_1); // scope 0 at $DIR/mem_replace.rs:+1:16: +1:18 (*_1) = _2; // scope 1 at $DIR/mem_replace.rs:+2:5: +2:11 - _0 = _3; // scope 1 at $DIR/mem_replace.rs:+3:5: +3:9 - StorageDead(_3); // scope 0 at $DIR/mem_replace.rs:+4:1: +4:2 return; // scope 0 at $DIR/mem_replace.rs:+4:2: +4:2 } } diff --git a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.mir index 619db12c48b..50e0538c133 100644 --- a/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/mem_replace.mem_replace.PreCodegen.after.mir @@ -7,29 +7,28 @@ fn mem_replace(_1: &mut u32, _2: u32) -> u32 { scope 1 (inlined std::mem::replace::<u32>) { // at $DIR/mem_replace.rs:16:5: 16:28 debug dest => _1; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL debug src => _2; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - let mut _4: *const u32; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - let mut _5: *mut u32; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + let mut _3: *const u32; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + let mut _4: *mut u32; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL scope 2 { - let _3: u32; // in scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL scope 3 { - debug result => _3; // in scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + debug result => _0; // in scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL scope 7 (inlined std::ptr::write::<u32>) { // at $SRC_DIR/core/src/mem/mod.rs:LL:COL - debug dst => _5; // in scope 7 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + debug dst => _4; // in scope 7 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL debug src => _2; // in scope 7 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - let mut _7: *mut u32; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + let mut _6: *mut u32; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 8 { scope 9 (inlined std::ptr::write::runtime::<u32>) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL - debug dst => _7; // in scope 9 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug dst => _6; // in scope 9 at $SRC_DIR/core/src/intrinsics.rs:LL:COL } } } } scope 4 (inlined std::ptr::read::<u32>) { // at $SRC_DIR/core/src/mem/mod.rs:LL:COL - debug src => _4; // in scope 4 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - let mut _6: *const u32; // in scope 4 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug src => _3; // in scope 4 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _5: *const u32; // in scope 4 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 5 { scope 6 (inlined std::ptr::read::runtime::<u32>) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL - debug src => _6; // in scope 6 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug src => _5; // in scope 6 at $SRC_DIR/core/src/intrinsics.rs:LL:COL } } } @@ -38,20 +37,17 @@ fn mem_replace(_1: &mut u32, _2: u32) -> u32 { bb0: { StorageLive(_3); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - StorageLive(_4); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - _4 = &raw const (*_1); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - StorageLive(_6); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - _3 = (*_4); // scope 5 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - StorageDead(_6); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - StorageDead(_4); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - StorageLive(_5); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - _5 = &raw mut (*_1); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - StorageLive(_7); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - (*_5) = _2; // scope 8 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - StorageDead(_7); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - StorageDead(_5); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL - _0 = move _3; // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + _3 = &raw const (*_1); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + StorageLive(_5); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + _0 = (*_3); // scope 5 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageDead(_5); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageDead(_3); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + StorageLive(_4); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + _4 = &raw mut (*_1); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + StorageLive(_6); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + (*_4) = _2; // scope 8 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageDead(_6); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + StorageDead(_4); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL return; // scope 0 at $DIR/mem_replace.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir index 7d4766ee5cc..7a10b929ebd 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.mir @@ -7,63 +7,62 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> scope 1 (inlined core::slice::<impl [u32]>::get_unchecked_mut::<std::ops::Range<usize>>) { // at $DIR/slice_index.rs:26:11: 26:35 debug self => _1; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL debug index => _2; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - let mut _3: &mut [u32]; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + let mut _3: *mut [u32]; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL let mut _4: *mut [u32]; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - let mut _5: *mut [u32]; // in scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL scope 2 { scope 3 (inlined <std::ops::Range<usize> as SliceIndex<[u32]>>::get_unchecked_mut) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL debug self => _2; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug slice => _5; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let _6: std::ops::Range<usize>; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + debug slice => _4; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let _5: std::ops::Range<usize>; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _7: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL let mut _8: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _9: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _9: *mut u32; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL let mut _10: *mut u32; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _11: *mut u32; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let mut _11: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL let mut _12: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _13: usize; // in scope 3 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let mut _14: std::ops::Range<usize>; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL - let mut _15: *mut [u32]; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + let mut _13: std::ops::Range<usize>; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + let mut _14: *mut [u32]; // in scope 3 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 4 { - debug this => _6; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL + debug this => _5; // in scope 4 at $SRC_DIR/core/src/slice/index.rs:LL:COL scope 5 { - let _7: usize; // in scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let _6: usize; // in scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL scope 6 { - debug new_len => _7; // in scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + debug new_len => _6; // in scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL scope 11 (inlined ptr::mut_ptr::<impl *mut [u32]>::as_mut_ptr) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _5; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _4; // in scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL } scope 12 (inlined ptr::mut_ptr::<impl *mut u32>::add) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _11; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - debug count => _12; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _10; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug count => _11; // in scope 12 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 13 { } } scope 14 (inlined slice_from_raw_parts_mut::<u32>) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug data => _10; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - debug len => _13; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + debug data => _9; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + debug len => _12; // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + let mut _16: *mut (); // in scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL scope 15 (inlined ptr::mut_ptr::<impl *mut u32>::cast::<()>) { // at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - debug self => _10; // in scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - let mut _17: *mut (); // in scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _9; // in scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL } scope 16 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { // at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - debug data_address => _17; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - debug metadata => _13; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - let mut _18: std::ptr::metadata::PtrRepr<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - let mut _19: std::ptr::metadata::PtrComponents<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - let mut _20: *const (); // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + debug data_address => _16; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + debug metadata => _12; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + let mut _17: std::ptr::metadata::PtrRepr<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + let mut _18: std::ptr::metadata::PtrComponents<[u32]>; // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + let mut _19: *const (); // in scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL scope 17 { } } } } scope 7 (inlined <std::ops::Range<usize> as SliceIndex<[T]>>::get_unchecked_mut::runtime::<u32>) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL - debug this => _14; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL - debug slice => _15; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug this => _13; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug slice => _14; // in scope 7 at $SRC_DIR/core/src/intrinsics.rs:LL:COL scope 8 (inlined ptr::mut_ptr::<impl *mut [u32]>::len) { // at $SRC_DIR/core/src/slice/index.rs:LL:COL - debug self => _15; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - let mut _16: *const [u32]; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _14; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + let mut _15: *const [u32]; // in scope 8 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL scope 9 (inlined std::ptr::metadata::<[u32]>) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - debug ptr => _16; // in scope 9 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + debug ptr => _15; // in scope 9 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL scope 10 { } } @@ -76,61 +75,60 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range<usize>) -> } bb0: { + StorageLive(_3); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL StorageLive(_4); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _4 = &raw mut (*_1); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL StorageLive(_5); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _5 = &raw mut (*_1); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_6); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_13); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL StorageLive(_14); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL StorageLive(_15); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageLive(_16); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_6); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_7); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _7 = (_2.1: usize); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_8); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _8 = (_2.1: usize); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_9); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _9 = (_2.0: usize); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _7 = unchecked_sub::<usize>(move _8, move _9) -> [return: bb1, unwind unreachable]; // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _8 = (_2.0: usize); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _6 = unchecked_sub::<usize>(move _7, move _8) -> [return: bb1, unwind unreachable]; // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/slice/index.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(usize, usize) -> usize {unchecked_sub::<usize>}, val: Value(<ZST>) } } bb1: { - StorageDead(_9); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_8); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_7); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_9); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageLive(_10); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _10 = _4 as *mut u32 (PtrToPtr); // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL StorageLive(_11); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _11 = _5 as *mut u32 (PtrToPtr); // scope 11 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageLive(_12); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _12 = (_2.0: usize); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _10 = Offset(_11, _12); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL - StorageDead(_12); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _11 = (_2.0: usize); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _9 = Offset(_10, _11); // scope 13 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL StorageDead(_11); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_13); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _13 = _7; // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageLive(_17); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _17 = _10 as *mut () (PtrToPtr); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + StorageDead(_10); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_12); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _12 = _6; // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_16); // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _16 = _9 as *mut () (PtrToPtr); // scope 15 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + StorageLive(_17); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL StorageLive(_18); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL StorageLive(_19); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageLive(_20); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - _20 = _17 as *const () (Pointer(MutToConstPointer)); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - _19 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _20, metadata: _13 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageDead(_20); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - _18 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _19 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + _19 = _16 as *const () (Pointer(MutToConstPointer)); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + _18 = ptr::metadata::PtrComponents::<[u32]> { data_address: move _19, metadata: _12 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL StorageDead(_19); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - _4 = (_18.1: *mut [u32]); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageDead(_18); // scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL - StorageDead(_17); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_13); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_10); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_7); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_16); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _17 = ptr::metadata::PtrRepr::<[u32]> { const_ptr: move _18 }; // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageDead(_18); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + _3 = (_17.1: *mut [u32]); // scope 17 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageDead(_17); // scope 16 at $SRC_DIR/core/src/ptr/metadata.rs:LL:COL + StorageDead(_16); // scope 14 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageDead(_12); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_9); // scope 6 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_6); // scope 5 at $SRC_DIR/core/src/slice/index.rs:LL:COL StorageDead(_15); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL StorageDead(_14); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_6); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_13); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL StorageDead(_5); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _3 = &mut (*_4); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - StorageDead(_4); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - _0 = _3; // scope 0 at $DIR/slice_index.rs:+1:5: +1:35 + StorageDead(_4); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _0 = &mut (*_3); // scope 2 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_3); // scope 1 at $SRC_DIR/core/src/slice/mod.rs:LL:COL return; // scope 0 at $DIR/slice_index.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.mir index d3b59e265b2..dcf79a4a4e7 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_index_range.PreCodegen.after.mir @@ -4,25 +4,23 @@ fn slice_index_range(_1: &[u32], _2: std::ops::Range<usize>) -> &[u32] { debug slice => _1; // in scope 0 at $DIR/slice_index.rs:+0:26: +0:31 debug index => _2; // in scope 0 at $DIR/slice_index.rs:+0:41: +0:46 let mut _0: &[u32]; // return place in scope 0 at $DIR/slice_index.rs:+0:65: +0:71 - let _3: &[u32]; // in scope 0 at $DIR/slice_index.rs:+1:6: +1:18 scope 1 (inlined #[track_caller] core::slice::index::<impl Index<std::ops::Range<usize>> for [u32]>::index) { // at $DIR/slice_index.rs:21:6: 21:18 debug self => _1; // in scope 1 at $SRC_DIR/core/src/slice/index.rs:LL:COL debug index => _2; // in scope 1 at $SRC_DIR/core/src/slice/index.rs:LL:COL - let _4: &[u32]; // in scope 1 at $SRC_DIR/core/src/slice/index.rs:LL:COL + let _3: &[u32]; // in scope 1 at $SRC_DIR/core/src/slice/index.rs:LL:COL } bb0: { - StorageLive(_4); // scope 1 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _4 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, _1) -> bb1; // scope 1 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageLive(_3); // scope 1 at $SRC_DIR/core/src/slice/index.rs:LL:COL + _3 = <std::ops::Range<usize> as SliceIndex<[u32]>>::index(move _2, _1) -> bb1; // scope 1 at $SRC_DIR/core/src/slice/index.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/slice/index.rs:LL:COL // + literal: Const { ty: for<'a> fn(std::ops::Range<usize>, &'a [u32]) -> &'a <std::ops::Range<usize> as SliceIndex<[u32]>>::Output {<std::ops::Range<usize> as SliceIndex<[u32]>>::index}, val: Value(<ZST>) } } bb1: { - _3 = _4; // scope 1 at $SRC_DIR/core/src/slice/index.rs:LL:COL - StorageDead(_4); // scope 1 at $SRC_DIR/core/src/slice/index.rs:LL:COL - _0 = _3; // scope 0 at $DIR/slice_index.rs:+1:5: +1:18 + _0 = _3; // scope 1 at $SRC_DIR/core/src/slice/index.rs:LL:COL + StorageDead(_3); // scope 1 at $SRC_DIR/core/src/slice/index.rs:LL:COL return; // scope 0 at $DIR/slice_index.rs:+2:2: +2:2 } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir index f27525bf3d9..0da7e5536ae 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.mir @@ -6,58 +6,120 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { let mut _0: (); // return place in scope 0 at $DIR/slice_iter.rs:+0:60: +0:60 let mut _3: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 let mut _4: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _5: std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let _6: (); // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _7: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _8: &mut std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - let mut _9: isize; // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6 - let mut _11: &impl Fn(&T); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10 - let mut _12: (&T,); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13 + let _5: (); // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _6: std::option::Option<&T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _7: &mut std::slice::Iter<'_, T>; // in scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + let mut _8: isize; // in scope 0 at $DIR/slice_iter.rs:+1:5: +3:6 + let mut _10: &impl Fn(&T); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:10 + let mut _11: (&T,); // in scope 0 at $DIR/slice_iter.rs:+2:9: +2:13 scope 1 { - debug iter => _5; // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - let _10: &T; // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 + debug iter => _4; // in scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + let _9: &T; // in scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 scope 2 { - debug x => _10; // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10 + debug x => _9; // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10 } } scope 3 (inlined core::slice::<impl [T]>::iter) { // at $DIR/slice_iter.rs:28:20: 28:26 debug self => _1; // in scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + scope 4 (inlined std::slice::Iter::<'_, T>::new) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL + debug slice => _1; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let _12: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _14: bool; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _15: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _16: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _17: std::ptr::NonNull<T>; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _18: *mut T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _19: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + scope 5 { + debug ptr => _12; // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + scope 6 { + let _13: *const T; // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + scope 7 { + debug end => _13; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + scope 13 (inlined NonNull::<T>::new_unchecked) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug ptr => _18; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + let mut _21: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + let mut _22: *mut T; // in scope 13 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + scope 14 { + scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug ptr => _22; // in scope 15 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null) { // at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + debug self => _22; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + let mut _23: *mut u8; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + scope 17 { + scope 18 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug ptr => _23; // in scope 18 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _23; // in scope 19 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + scope 20 { + scope 21 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _23; // in scope 21 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + } + } + } + } + } + } + } + } + } + } + scope 9 (inlined invalid::<T>) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug addr => _15; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + scope 10 { + } + } + scope 11 (inlined ptr::const_ptr::<impl *const T>::add) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug self => _12; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + debug count => _16; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + scope 12 { + } + } + } + } + scope 8 (inlined core::slice::<impl [T]>::as_ptr) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug self => _1; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + let mut _20: *const [T]; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + } + } } - scope 4 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) { // at $DIR/slice_iter.rs:28:14: 28:26 - debug self => _4; // in scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + scope 22 (inlined <std::slice::Iter<'_, T> as IntoIterator>::into_iter) { // at $DIR/slice_iter.rs:28:14: 28:26 + debug self => _3; // in scope 22 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL } bb0: { - StorageLive(_3); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - StorageLive(_4); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - _4 = std::slice::Iter::<'_, T>::new(_1) -> [return: bb10, unwind: bb8]; // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/slice/mod.rs:LL:COL - // + user_ty: UserType(0) - // + literal: Const { ty: fn(&[T]) -> std::slice::Iter<'_, T> {std::slice::Iter::<'_, T>::new}, val: Value(<ZST>) } + StorageLive(_12); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_20); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _20 = &raw const (*_1); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _12 = move _20 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_20); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_13); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_14); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _14 = const _; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + switchInt(move _14) -> [0: bb11, otherwise: bb10]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb1: { - StorageLive(_7); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - _8 = &mut _5; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - _7 = <std::slice::Iter<'_, T> as Iterator>::next(_8) -> [return: bb2, unwind: bb8]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + StorageLive(_6); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + _7 = &mut _4; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + _6 = <std::slice::Iter<'_, T> as Iterator>::next(_7) -> [return: bb2, unwind: bb8]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 // mir::Constant // + span: $DIR/slice_iter.rs:28:14: 28:26 // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option<<std::slice::Iter<'_, T> as Iterator>::Item> {<std::slice::Iter<'_, T> as Iterator>::next}, val: Value(<ZST>) } } bb2: { - _9 = discriminant(_7); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 - switchInt(move _9) -> [0: bb5, 1: bb3, otherwise: bb4]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + _8 = discriminant(_6); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 + switchInt(move _8) -> [0: bb5, 1: bb3, otherwise: bb4]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:26 } bb3: { - _10 = ((_7 as Some).0: &T); // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 - StorageLive(_11); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 - _11 = &_2; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 - StorageLive(_12); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 - _12 = (_10,); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 - _6 = <impl Fn(&T) as Fn<(&T,)>>::call(move _11, move _12) -> [return: bb6, unwind: bb8]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + _9 = ((_6 as Some).0: &T); // scope 1 at $DIR/slice_iter.rs:+1:9: +1:10 + StorageLive(_10); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 + _10 = &_2; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:10 + StorageLive(_11); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + _11 = (_9,); // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 + _5 = <impl Fn(&T) as Fn<(&T,)>>::call(move _10, move _11) -> [return: bb6, unwind: bb8]; // scope 2 at $DIR/slice_iter.rs:+2:9: +2:13 // mir::Constant // + span: $DIR/slice_iter.rs:29:9: 29:10 // + literal: Const { ty: for<'a> extern "rust-call" fn(&'a impl Fn(&T), (&T,)) -> <impl Fn(&T) as FnOnce<(&T,)>>::Output {<impl Fn(&T) as Fn<(&T,)>>::call}, val: Value(<ZST>) } @@ -68,16 +130,15 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb5: { - StorageDead(_7); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 - StorageDead(_5); // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6 - StorageDead(_3); // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6 + StorageDead(_6); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 + StorageDead(_4); // scope 0 at $DIR/slice_iter.rs:+3:5: +3:6 drop(_2) -> bb7; // scope 0 at $DIR/slice_iter.rs:+4:1: +4:2 } bb6: { - StorageDead(_12); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 StorageDead(_11); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 - StorageDead(_7); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 + StorageDead(_10); // scope 2 at $DIR/slice_iter.rs:+2:12: +2:13 + StorageDead(_6); // scope 1 at $DIR/slice_iter.rs:+3:5: +3:6 goto -> bb1; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 } @@ -94,10 +155,49 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb10: { - _3 = move _4; // scope 4 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/slice_iter.rs:+1:25: +1:26 - StorageLive(_5); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - _5 = move _3; // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + StorageLive(_15); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _15 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _13 = _15 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageDead(_15); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + goto -> bb12; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + } + + bb11: { + StorageLive(_16); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _16 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _13 = Offset(_12, _16); // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + StorageDead(_16); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + goto -> bb12; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + } + + bb12: { + StorageDead(_14); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_17); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_18); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _18 = _12 as *mut T (PtrToPtr); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_21); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _21 = _18 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + _17 = NonNull::<T> { pointer: _21 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + StorageDead(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_21); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_18); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_19); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _19 = _13; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _3 = std::slice::Iter::<'_, T> { ptr: move _17, end: move _19, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + // mir::Constant + // + span: no-location + // + literal: Const { ty: PhantomData<&T>, val: Value(<ZST>) } + // adt + // + user_ty: UserType(1) + StorageDead(_19); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_17); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_13); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_12); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_4); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 + _4 = move _3; // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 goto -> bb1; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir index 62dd9667d96..45b41b54c8b 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.mir @@ -19,39 +19,104 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { scope 2 { debug x => _10; // in scope 2 at $DIR/slice_iter.rs:+1:9: +1:10 } - scope 7 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) { // at $DIR/slice_iter.rs:35:14: 35:32 - debug self => _8; // in scope 7 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - let mut _13: &mut std::slice::Iter<'_, T>; // in scope 7 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + scope 25 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) { // at $DIR/slice_iter.rs:35:14: 35:32 + debug self => _8; // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + let mut _25: &mut std::slice::Iter<'_, T>; // in scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL } } scope 3 (inlined core::slice::<impl [T]>::iter) { // at $DIR/slice_iter.rs:35:20: 35:26 debug self => _1; // in scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + scope 4 (inlined std::slice::Iter::<'_, T>::new) { // at $SRC_DIR/core/src/slice/mod.rs:LL:COL + debug slice => _1; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let _13: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _15: bool; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _16: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _17: usize; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _18: std::ptr::NonNull<T>; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _19: *mut T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + let mut _20: *const T; // in scope 4 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + scope 5 { + debug ptr => _13; // in scope 5 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + scope 6 { + let _14: *const T; // in scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + scope 7 { + debug end => _14; // in scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + scope 13 (inlined NonNull::<T>::new_unchecked) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug ptr => _19; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + let mut _22: *const T; // in scope 13 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + let mut _23: *mut T; // in scope 13 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + scope 14 { + scope 15 (inlined NonNull::<T>::new_unchecked::runtime::<T>) { // at $SRC_DIR/core/src/intrinsics.rs:LL:COL + debug ptr => _23; // in scope 15 at $SRC_DIR/core/src/intrinsics.rs:LL:COL + scope 16 (inlined ptr::mut_ptr::<impl *mut T>::is_null) { // at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + debug self => _23; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + let mut _24: *mut u8; // in scope 16 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + scope 17 { + scope 18 (inlined ptr::mut_ptr::<impl *mut T>::is_null::runtime_impl) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug ptr => _24; // in scope 18 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + scope 19 (inlined ptr::mut_ptr::<impl *mut u8>::addr) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _24; // in scope 19 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + scope 20 { + scope 21 (inlined ptr::mut_ptr::<impl *mut u8>::cast::<()>) { // at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + debug self => _24; // in scope 21 at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + } + } + } + } + } + } + } + } + } + } + scope 9 (inlined invalid::<T>) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug addr => _16; // in scope 9 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + scope 10 { + } + } + scope 11 (inlined ptr::const_ptr::<impl *const T>::add) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug self => _13; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + debug count => _17; // in scope 11 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + scope 12 { + } + } + } + } + scope 8 (inlined core::slice::<impl [T]>::as_ptr) { // at $SRC_DIR/core/src/slice/iter.rs:LL:COL + debug self => _1; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + let mut _21: *const [T]; // in scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + } + } } - scope 4 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) { // at $DIR/slice_iter.rs:35:27: 35:32 - debug self => _4; // in scope 4 at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - scope 5 (inlined Rev::<std::slice::Iter<'_, T>>::new) { // at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - debug iter => _4; // in scope 5 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + scope 22 (inlined <std::slice::Iter<'_, T> as Iterator>::rev) { // at $DIR/slice_iter.rs:35:27: 35:32 + debug self => _4; // in scope 22 at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + scope 23 (inlined Rev::<std::slice::Iter<'_, T>>::new) { // at $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + debug iter => _4; // in scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL } } - scope 6 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) { // at $DIR/slice_iter.rs:35:14: 35:32 - debug self => _3; // in scope 6 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL + scope 24 (inlined <Rev<std::slice::Iter<'_, T>> as IntoIterator>::into_iter) { // at $DIR/slice_iter.rs:35:14: 35:32 + debug self => _3; // in scope 24 at $SRC_DIR/core/src/iter/traits/collect.rs:LL:COL } bb0: { StorageLive(_4); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:26 - _4 = std::slice::Iter::<'_, T>::new(_1) -> [return: bb9, unwind: bb7]; // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL - // mir::Constant - // + span: $SRC_DIR/core/src/slice/mod.rs:LL:COL - // + user_ty: UserType(0) - // + literal: Const { ty: fn(&[T]) -> std::slice::Iter<'_, T> {std::slice::Iter::<'_, T>::new}, val: Value(<ZST>) } + StorageLive(_13); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_21); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _21 = &raw const (*_1); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _13 = move _21 as *const T (PtrToPtr); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageDead(_21); // scope 8 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + StorageLive(_14); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_15); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _15 = const _; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + switchInt(move _15) -> [0: bb10, otherwise: bb9]; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL } bb1: { StorageLive(_7); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 _8 = &mut _5; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 - StorageLive(_13); // scope 7 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - _13 = &mut ((*_8).0: std::slice::Iter<'_, T>); // scope 7 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL - _7 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _13) -> [return: bb10, unwind: bb7]; // scope 7 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + StorageLive(_25); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + _25 = &mut ((*_8).0: std::slice::Iter<'_, T>); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + _7 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _25) -> [return: bb12, unwind: bb7]; // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL // + literal: Const { ty: for<'a> fn(&'a mut std::slice::Iter<'_, T>) -> Option<<std::slice::Iter<'_, T> as Iterator>::Item> {<std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back}, val: Value(<ZST>) } @@ -99,15 +164,56 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb9: { - _3 = Rev::<std::slice::Iter<'_, T>> { iter: move _4 }; // scope 5 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + StorageLive(_16); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _16 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _14 = _16 as *const T (Transmute); // scope 10 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + StorageDead(_16); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + goto -> bb11; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + } + + bb10: { + StorageLive(_17); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _17 = Len((*_1)); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _14 = Offset(_13, _17); // scope 12 at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + StorageDead(_17); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + goto -> bb11; // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + } + + bb11: { + StorageDead(_15); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_18); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_19); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _19 = _13 as *mut T (PtrToPtr); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_24); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _22 = _19 as *const T (Pointer(MutToConstPointer)); // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + _18 = NonNull::<T> { pointer: _22 }; // scope 14 at $SRC_DIR/core/src/ptr/non_null.rs:LL:COL + StorageDead(_24); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_23); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_22); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_19); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageLive(_20); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _20 = _14; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + _4 = std::slice::Iter::<'_, T> { ptr: move _18, end: move _20, _marker: const ZeroSized: PhantomData<&T> }; // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + // mir::Constant + // + span: no-location + // + literal: Const { ty: PhantomData<&T>, val: Value(<ZST>) } + // adt + // + user_ty: UserType(1) + StorageDead(_20); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_18); // scope 7 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_14); // scope 6 at $SRC_DIR/core/src/slice/iter.rs:LL:COL + StorageDead(_13); // scope 3 at $SRC_DIR/core/src/slice/mod.rs:LL:COL + _3 = Rev::<std::slice::Iter<'_, T>> { iter: move _4 }; // scope 23 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL StorageDead(_4); // scope 0 at $DIR/slice_iter.rs:+1:31: +1:32 StorageLive(_5); // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 _5 = move _3; // scope 0 at $DIR/slice_iter.rs:+1:14: +1:32 goto -> bb1; // scope 1 at $DIR/slice_iter.rs:+1:5: +3:6 } - bb10: { - StorageDead(_13); // scope 7 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL + bb12: { + StorageDead(_25); // scope 25 at $SRC_DIR/core/src/iter/adapters/rev.rs:LL:COL _9 = discriminant(_7); // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 switchInt(move _9) -> [0: bb4, 1: bb2, otherwise: bb3]; // scope 1 at $DIR/slice_iter.rs:+1:14: +1:32 } diff --git a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff new file mode 100644 index 00000000000..07bd48fc846 --- /dev/null +++ b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff @@ -0,0 +1,175 @@ +- // MIR for `debuginfo` before ReferencePropagation ++ // MIR for `debuginfo` after ReferencePropagation + + fn debuginfo() -> () { + let mut _0: (); // return place in scope 0 at $DIR/reference_prop.rs:+0:16: +0:16 + let _1: &mut u8; // in scope 0 at $DIR/reference_prop.rs:+3:9: +3:19 + let mut _2: u8; // in scope 0 at $DIR/reference_prop.rs:+3:27: +3:31 + let _4: debuginfo::T; // in scope 0 at $DIR/reference_prop.rs:+4:18: +4:22 + let _6: (); // in scope 0 at $DIR/reference_prop.rs:+9:5: +12:6 + let mut _7: std::option::Option<i32>; // in scope 0 at $DIR/reference_prop.rs:+9:11: +9:18 + let mut _8: isize; // in scope 0 at $DIR/reference_prop.rs:+10:9: +10:13 + let _10: (); // in scope 0 at $DIR/reference_prop.rs:+16:5: +17:6 + let mut _11: &[i32]; // in scope 0 at $DIR/reference_prop.rs:+16:82: +16:94 + let _12: &[i32]; // in scope 0 at $DIR/reference_prop.rs:+16:83: +16:94 + let mut _13: &[i32; 10]; // in scope 0 at $DIR/reference_prop.rs:+16:83: +16:90 + let _14: [i32; 10]; // in scope 0 at $DIR/reference_prop.rs:+16:83: +16:90 + let mut _15: std::ops::RangeFull; // in scope 0 at $DIR/reference_prop.rs:+16:91: +16:93 + let mut _16: usize; // in scope 0 at $DIR/reference_prop.rs:+16:12: +16:79 + let mut _17: usize; // in scope 0 at $DIR/reference_prop.rs:+16:12: +16:79 + let mut _18: bool; // in scope 0 at $DIR/reference_prop.rs:+16:12: +16:79 + let _23: &&mut u8; // in scope 0 at $DIR/reference_prop.rs:+19:28: +19:40 + let _24: &mut u8; // in scope 0 at $DIR/reference_prop.rs:+19:29: +19:40 + let mut _25: debuginfo::T; // in scope 0 at $DIR/reference_prop.rs:+19:34: +19:38 + scope 1 { +- debug ref_mut_u8 => _1; // in scope 1 at $DIR/reference_prop.rs:+3:9: +3:19 ++ debug ref_mut_u8 => &_2; // in scope 1 at $DIR/reference_prop.rs:+3:9: +3:19 + let _3: &u8; // in scope 1 at $DIR/reference_prop.rs:+4:9: +4:14 + let mut _28: &debuginfo::T; // in scope 1 at $DIR/reference_prop.rs:+4:17: +4:24 + scope 2 { +- debug field => _3; // in scope 2 at $DIR/reference_prop.rs:+4:9: +4:14 ++ debug field => &((*_28).0: u8); // in scope 2 at $DIR/reference_prop.rs:+4:9: +4:14 + let _5: &u8; // in scope 2 at $DIR/reference_prop.rs:+7:9: +7:17 + scope 3 { +- debug reborrow => _5; // in scope 3 at $DIR/reference_prop.rs:+7:9: +7:17 ++ debug reborrow => &_2; // in scope 3 at $DIR/reference_prop.rs:+7:9: +7:17 + let _9: &i32; // in scope 3 at $DIR/reference_prop.rs:+11:14: +11:31 + let _22: &&&mut u8; // in scope 3 at $DIR/reference_prop.rs:+19:9: +19:24 + let mut _27: &std::option::Option<i32>; // in scope 3 at $DIR/reference_prop.rs:+11:14: +11:31 + scope 4 { +- debug variant_field => _9; // in scope 4 at $DIR/reference_prop.rs:+11:14: +11:31 ++ debug variant_field => &(((*_27) as Some).0: i32); // in scope 4 at $DIR/reference_prop.rs:+11:14: +11:31 + } + scope 5 { +- debug constant_index => _19; // in scope 5 at $DIR/reference_prop.rs:+16:16: +16:34 ++ debug constant_index => &(*_11)[1 of 3]; // in scope 5 at $DIR/reference_prop.rs:+16:16: +16:34 + debug subslice => _20; // in scope 5 at $DIR/reference_prop.rs:+16:36: +16:44 + debug constant_index_from_end => _21; // in scope 5 at $DIR/reference_prop.rs:+16:51: +16:78 + let _19: &i32; // in scope 5 at $DIR/reference_prop.rs:+16:16: +16:34 + let _20: &[i32]; // in scope 5 at $DIR/reference_prop.rs:+16:36: +16:44 + let _21: &i32; // in scope 5 at $DIR/reference_prop.rs:+16:51: +16:78 + let mut _26: &[i32; 10]; // in scope 5 at $DIR/reference_prop.rs:+16:83: +16:90 + } + scope 6 { +- debug multiple_borrow => _22; // in scope 6 at $DIR/reference_prop.rs:+19:9: +19:24 ++ debug multiple_borrow => &&&(_25.0: u8); // in scope 6 at $DIR/reference_prop.rs:+19:9: +19:24 + } + } + } + } + + bb0: { +- StorageLive(_1); // scope 0 at $DIR/reference_prop.rs:+3:9: +3:19 + StorageLive(_2); // scope 0 at $DIR/reference_prop.rs:+3:27: +3:31 + _2 = const 5_u8; // scope 0 at $DIR/reference_prop.rs:+3:27: +3:31 +- _1 = &mut _2; // scope 0 at $DIR/reference_prop.rs:+3:22: +3:31 +- StorageLive(_3); // scope 1 at $DIR/reference_prop.rs:+4:9: +4:14 + _28 = const _; // scope 1 at $DIR/reference_prop.rs:+4:17: +4:24 + // mir::Constant + // + span: $DIR/reference_prop.rs:535:17: 535:24 + // + literal: Const { ty: &T, val: Unevaluated(debuginfo, [], Some(promoted[2])) } +- _3 = &((*_28).0: u8); // scope 1 at $DIR/reference_prop.rs:+4:17: +4:24 +- StorageLive(_5); // scope 2 at $DIR/reference_prop.rs:+7:9: +7:17 +- _5 = &(*_1); // scope 2 at $DIR/reference_prop.rs:+7:20: +7:32 +- StorageLive(_6); // scope 3 at $DIR/reference_prop.rs:+9:5: +12:6 + StorageLive(_7); // scope 3 at $DIR/reference_prop.rs:+9:11: +9:18 + _7 = Option::<i32>::Some(const 0_i32); // scope 3 at $DIR/reference_prop.rs:+9:11: +9:18 + _8 = discriminant(_7); // scope 3 at $DIR/reference_prop.rs:+9:11: +9:18 + switchInt(move _8) -> [0: bb3, 1: bb1, otherwise: bb2]; // scope 3 at $DIR/reference_prop.rs:+9:5: +9:18 + } + + bb1: { +- StorageLive(_9); // scope 3 at $DIR/reference_prop.rs:+11:14: +11:31 + _27 = const _; // scope 3 at $DIR/reference_prop.rs:+11:14: +11:31 + // mir::Constant + // + span: $DIR/reference_prop.rs:542:14: 542:31 + // + literal: Const { ty: &Option<i32>, val: Unevaluated(debuginfo, [], Some(promoted[1])) } +- _9 = &(((*_27) as Some).0: i32); // scope 3 at $DIR/reference_prop.rs:+11:14: +11:31 +- _6 = const (); // scope 4 at $DIR/reference_prop.rs:+11:36: +11:38 +- StorageDead(_9); // scope 3 at $DIR/reference_prop.rs:+11:37: +11:38 + goto -> bb4; // scope 3 at $DIR/reference_prop.rs:+11:37: +11:38 + } + + bb2: { + unreachable; // scope 3 at $DIR/reference_prop.rs:+9:11: +9:18 + } + + bb3: { +- _6 = const (); // scope 3 at $DIR/reference_prop.rs:+10:17: +10:19 + goto -> bb4; // scope 3 at $DIR/reference_prop.rs:+10:17: +10:19 + } + + bb4: { + StorageDead(_7); // scope 3 at $DIR/reference_prop.rs:+12:5: +12:6 +- StorageDead(_6); // scope 3 at $DIR/reference_prop.rs:+12:5: +12:6 +- StorageLive(_10); // scope 3 at $DIR/reference_prop.rs:+16:5: +17:6 + StorageLive(_11); // scope 5 at $DIR/reference_prop.rs:+16:82: +16:94 + StorageLive(_12); // scope 5 at $DIR/reference_prop.rs:+16:83: +16:94 + StorageLive(_13); // scope 5 at $DIR/reference_prop.rs:+16:83: +16:90 + _26 = const _; // scope 5 at $DIR/reference_prop.rs:+16:83: +16:90 + // mir::Constant + // + span: $DIR/reference_prop.rs:547:83: 547:90 + // + literal: Const { ty: &[i32; 10], val: Unevaluated(debuginfo, [], Some(promoted[0])) } + _13 = &(*_26); // scope 5 at $DIR/reference_prop.rs:+16:83: +16:90 + StorageLive(_15); // scope 5 at $DIR/reference_prop.rs:+16:91: +16:93 + _15 = RangeFull; // scope 5 at $DIR/reference_prop.rs:+16:91: +16:93 + _12 = <[i32; 10] as Index<RangeFull>>::index(move _13, move _15) -> bb5; // scope 5 at $DIR/reference_prop.rs:+16:83: +16:94 + // mir::Constant + // + span: $DIR/reference_prop.rs:547:83: 547:94 + // + literal: Const { ty: for<'a> fn(&'a [i32; 10], RangeFull) -> &'a <[i32; 10] as Index<RangeFull>>::Output {<[i32; 10] as Index<RangeFull>>::index}, val: Value(<ZST>) } + } + + bb5: { + StorageDead(_15); // scope 5 at $DIR/reference_prop.rs:+16:93: +16:94 + StorageDead(_13); // scope 5 at $DIR/reference_prop.rs:+16:93: +16:94 + _11 = &(*_12); // scope 5 at $DIR/reference_prop.rs:+16:82: +16:94 + _16 = Len((*_11)); // scope 5 at $DIR/reference_prop.rs:+16:12: +16:79 + _17 = const 3_usize; // scope 5 at $DIR/reference_prop.rs:+16:12: +16:79 + _18 = Ge(move _16, move _17); // scope 5 at $DIR/reference_prop.rs:+16:12: +16:79 + switchInt(move _18) -> [0: bb7, otherwise: bb6]; // scope 5 at $DIR/reference_prop.rs:+16:12: +16:79 + } + + bb6: { +- StorageLive(_19); // scope 5 at $DIR/reference_prop.rs:+16:16: +16:34 +- _19 = &(*_11)[1 of 3]; // scope 5 at $DIR/reference_prop.rs:+16:16: +16:34 + StorageLive(_20); // scope 5 at $DIR/reference_prop.rs:+16:36: +16:44 + _20 = &(*_11)[2:-1]; // scope 5 at $DIR/reference_prop.rs:+16:36: +16:44 + StorageLive(_21); // scope 5 at $DIR/reference_prop.rs:+16:51: +16:78 + _21 = &(*_11)[-1 of 3]; // scope 5 at $DIR/reference_prop.rs:+16:51: +16:78 +- _10 = const (); // scope 5 at $DIR/reference_prop.rs:+16:95: +17:6 + StorageDead(_21); // scope 3 at $DIR/reference_prop.rs:+17:5: +17:6 + StorageDead(_20); // scope 3 at $DIR/reference_prop.rs:+17:5: +17:6 +- StorageDead(_19); // scope 3 at $DIR/reference_prop.rs:+17:5: +17:6 + goto -> bb8; // scope 3 at $DIR/reference_prop.rs:+16:5: +17:6 + } + + bb7: { +- _10 = const (); // scope 3 at $DIR/reference_prop.rs:+17:6: +17:6 + goto -> bb8; // scope 3 at $DIR/reference_prop.rs:+16:5: +17:6 + } + + bb8: { + StorageDead(_12); // scope 3 at $DIR/reference_prop.rs:+17:5: +17:6 + StorageDead(_11); // scope 3 at $DIR/reference_prop.rs:+17:5: +17:6 +- StorageDead(_10); // scope 3 at $DIR/reference_prop.rs:+17:5: +17:6 +- StorageLive(_22); // scope 3 at $DIR/reference_prop.rs:+19:9: +19:24 +- StorageLive(_23); // scope 3 at $DIR/reference_prop.rs:+19:28: +19:40 +- StorageLive(_24); // scope 3 at $DIR/reference_prop.rs:+19:29: +19:40 + StorageLive(_25); // scope 3 at $DIR/reference_prop.rs:+19:34: +19:38 + _25 = T(const 6_u8); // scope 3 at $DIR/reference_prop.rs:+19:34: +19:38 +- _24 = &mut (_25.0: u8); // scope 3 at $DIR/reference_prop.rs:+19:29: +19:40 +- _23 = &_24; // scope 3 at $DIR/reference_prop.rs:+19:28: +19:40 +- _22 = &_23; // scope 3 at $DIR/reference_prop.rs:+19:27: +19:40 + _0 = const (); // scope 0 at $DIR/reference_prop.rs:+0:16: +20:2 + StorageDead(_25); // scope 3 at $DIR/reference_prop.rs:+20:1: +20:2 +- StorageDead(_24); // scope 3 at $DIR/reference_prop.rs:+20:1: +20:2 +- StorageDead(_23); // scope 3 at $DIR/reference_prop.rs:+20:1: +20:2 +- StorageDead(_22); // scope 3 at $DIR/reference_prop.rs:+20:1: +20:2 +- StorageDead(_5); // scope 2 at $DIR/reference_prop.rs:+20:1: +20:2 +- StorageDead(_3); // scope 1 at $DIR/reference_prop.rs:+20:1: +20:2 + StorageDead(_2); // scope 0 at $DIR/reference_prop.rs:+20:1: +20:2 +- StorageDead(_1); // scope 0 at $DIR/reference_prop.rs:+20:1: +20:2 + return; // scope 0 at $DIR/reference_prop.rs:+20:2: +20:2 + } + } + diff --git a/tests/mir-opt/reference_prop.dominate_storage.ReferencePropagation.diff b/tests/mir-opt/reference_prop.dominate_storage.ReferencePropagation.diff index 8edc83cbf67..e158f64e9c3 100644 --- a/tests/mir-opt/reference_prop.dominate_storage.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.dominate_storage.ReferencePropagation.diff @@ -24,7 +24,7 @@ _5 = (*_2); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL _0 = opaque::<i32>(_5) -> bb3; // scope 0 at $DIR/reference_prop.rs:+16:13: +16:38 // mir::Constant - // + span: $DIR/reference_prop.rs:383:28: 383:34 + // + span: $DIR/reference_prop.rs:455:28: 455:34 // + literal: Const { ty: fn(i32) {opaque::<i32>}, val: Value(<ZST>) } } diff --git a/tests/mir-opt/reference_prop.maybe_dead.ReferencePropagation.diff b/tests/mir-opt/reference_prop.maybe_dead.ReferencePropagation.diff index 920755bdd1d..38ab16cedb7 100644 --- a/tests/mir-opt/reference_prop.maybe_dead.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.maybe_dead.ReferencePropagation.diff @@ -29,7 +29,7 @@ StorageDead(_3); // scope 0 at $DIR/reference_prop.rs:+21:13: +21:27 _0 = opaque::<i32>(_6) -> bb2; // scope 0 at $DIR/reference_prop.rs:+22:13: +22:38 // mir::Constant - // + span: $DIR/reference_prop.rs:417:28: 417:34 + // + span: $DIR/reference_prop.rs:489:28: 489:34 // + literal: Const { ty: fn(i32) {opaque::<i32>}, val: Value(<ZST>) } } @@ -37,7 +37,7 @@ _7 = (*_4); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL _0 = opaque::<i32>(_7) -> bb3; // scope 0 at $DIR/reference_prop.rs:+27:13: +27:38 // mir::Constant - // + span: $DIR/reference_prop.rs:422:28: 422:34 + // + span: $DIR/reference_prop.rs:494:28: 494:34 // + literal: Const { ty: fn(i32) {opaque::<i32>}, val: Value(<ZST>) } } @@ -45,7 +45,7 @@ _8 = (*_5); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL _0 = opaque::<i32>(_8) -> bb4; // scope 0 at $DIR/reference_prop.rs:+33:13: +33:43 // mir::Constant - // + span: $DIR/reference_prop.rs:428:33: 428:39 + // + span: $DIR/reference_prop.rs:500:33: 500:39 // + literal: Const { ty: fn(i32) {opaque::<i32>}, val: Value(<ZST>) } } diff --git a/tests/mir-opt/reference_prop.multiple_storage.ReferencePropagation.diff b/tests/mir-opt/reference_prop.multiple_storage.ReferencePropagation.diff index 07bfdf0b2f1..6e451786870 100644 --- a/tests/mir-opt/reference_prop.multiple_storage.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.multiple_storage.ReferencePropagation.diff @@ -16,7 +16,7 @@ _3 = (*_2); // scope 0 at $SRC_DIR/core/src/intrinsics/mir.rs:LL:COL _0 = opaque::<i32>(_3) -> bb1; // scope 0 at $DIR/reference_prop.rs:+14:13: +14:43 // mir::Constant - // + span: $DIR/reference_prop.rs:357:33: 357:39 + // + span: $DIR/reference_prop.rs:429:33: 429:39 // + literal: Const { ty: fn(i32) {opaque::<i32>}, val: Value(<ZST>) } } diff --git a/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff index af8ee2411d3..d99e110359f 100644 --- a/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff @@ -13,13 +13,16 @@ debug x => _1; // in scope 1 at $DIR/reference_prop.rs:+1:9: +1:14 let _2: &mut i32; // in scope 1 at $DIR/reference_prop.rs:+2:9: +2:13 scope 2 { - debug xref => _2; // in scope 2 at $DIR/reference_prop.rs:+2:9: +2:13 +- debug xref => _2; // in scope 2 at $DIR/reference_prop.rs:+2:9: +2:13 ++ debug xref => &_1; // in scope 2 at $DIR/reference_prop.rs:+2:9: +2:13 let _3: *mut i32; // in scope 2 at $DIR/reference_prop.rs:+3:9: +3:13 scope 3 { - debug xraw => _3; // in scope 3 at $DIR/reference_prop.rs:+3:9: +3:13 +- debug xraw => _3; // in scope 3 at $DIR/reference_prop.rs:+3:9: +3:13 ++ debug xraw => &_1; // in scope 3 at $DIR/reference_prop.rs:+3:9: +3:13 let _6: &i32; // in scope 3 at $DIR/reference_prop.rs:+4:9: +4:13 scope 4 { - debug xshr => _6; // in scope 4 at $DIR/reference_prop.rs:+4:9: +4:13 +- debug xshr => _6; // in scope 4 at $DIR/reference_prop.rs:+4:9: +4:13 ++ debug xshr => &_1; // in scope 4 at $DIR/reference_prop.rs:+4:9: +4:13 let _7: i32; // in scope 4 at $DIR/reference_prop.rs:+6:9: +6:10 scope 5 { debug a => _7; // in scope 5 at $DIR/reference_prop.rs:+6:9: +6:10 @@ -35,19 +38,17 @@ StorageLive(_1); // scope 0 at $DIR/reference_prop.rs:+1:9: +1:14 _1 = const 2_i32; // scope 0 at $DIR/reference_prop.rs:+1:17: +1:18 - StorageLive(_2); // scope 1 at $DIR/reference_prop.rs:+2:9: +2:13 - _2 = &mut _1; // scope 1 at $DIR/reference_prop.rs:+2:16: +2:22 - StorageLive(_3); // scope 2 at $DIR/reference_prop.rs:+3:9: +3:13 +- _2 = &mut _1; // scope 1 at $DIR/reference_prop.rs:+2:16: +2:22 +- StorageLive(_3); // scope 2 at $DIR/reference_prop.rs:+3:9: +3:13 - StorageLive(_4); // scope 2 at $DIR/reference_prop.rs:+3:16: +3:36 - StorageLive(_5); // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26 - _5 = &mut (*_2); // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26 - _4 = &raw mut (*_5); // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26 -+ _4 = &raw mut _1; // scope 2 at $DIR/reference_prop.rs:+3:16: +3:26 - _3 = _4; // scope 2 at $DIR/reference_prop.rs:+3:16: +3:36 +- _3 = _4; // scope 2 at $DIR/reference_prop.rs:+3:16: +3:36 - StorageDead(_5); // scope 2 at $DIR/reference_prop.rs:+3:36: +3:37 - StorageDead(_4); // scope 2 at $DIR/reference_prop.rs:+3:36: +3:37 - StorageLive(_6); // scope 3 at $DIR/reference_prop.rs:+4:9: +4:13 +- StorageLive(_6); // scope 3 at $DIR/reference_prop.rs:+4:9: +4:13 - _6 = &(*_2); // scope 3 at $DIR/reference_prop.rs:+4:16: +4:22 -+ _6 = &_1; // scope 3 at $DIR/reference_prop.rs:+4:16: +4:22 StorageLive(_7); // scope 4 at $DIR/reference_prop.rs:+6:9: +6:10 - _7 = (*_6); // scope 4 at $DIR/reference_prop.rs:+6:13: +6:18 - StorageLive(_8); // scope 5 at $DIR/reference_prop.rs:+7:5: +7:26 @@ -64,8 +65,8 @@ StorageDead(_10); // scope 5 at $DIR/reference_prop.rs:+8:10: +8:11 StorageDead(_9); // scope 5 at $DIR/reference_prop.rs:+8:10: +8:11 StorageDead(_7); // scope 4 at $DIR/reference_prop.rs:+9:1: +9:2 - StorageDead(_6); // scope 3 at $DIR/reference_prop.rs:+9:1: +9:2 - StorageDead(_3); // scope 2 at $DIR/reference_prop.rs:+9:1: +9:2 +- StorageDead(_6); // scope 3 at $DIR/reference_prop.rs:+9:1: +9:2 +- StorageDead(_3); // scope 2 at $DIR/reference_prop.rs:+9:1: +9:2 - StorageDead(_2); // scope 1 at $DIR/reference_prop.rs:+9:1: +9:2 StorageDead(_1); // scope 0 at $DIR/reference_prop.rs:+9:1: +9:2 return; // scope 0 at $DIR/reference_prop.rs:+9:2: +9:2 diff --git a/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff index e41fc28461a..7b31ee695ce 100644 --- a/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.reference_propagation.ReferencePropagation.diff @@ -17,12 +17,12 @@ let mut _17: (); // in scope 0 at $DIR/reference_prop.rs:+17:16: +17:18 let _18: (); // in scope 0 at $DIR/reference_prop.rs:+21:5: +27:6 let _19: usize; // in scope 0 at $DIR/reference_prop.rs:+22:13: +22:14 - let _23: (); // in scope 0 at $DIR/reference_prop.rs:+26:9: +26:19 - let mut _24: (); // in scope 0 at $DIR/reference_prop.rs:+26:16: +26:18 + let _23: (); // in scope 0 at $DIR/reference_prop.rs:+26:9: +26:18 + let mut _24: &&usize; // in scope 0 at $DIR/reference_prop.rs:+26:16: +26:17 let _25: (); // in scope 0 at $DIR/reference_prop.rs:+30:5: +36:6 let _26: usize; // in scope 0 at $DIR/reference_prop.rs:+31:13: +31:14 - let _30: (); // in scope 0 at $DIR/reference_prop.rs:+35:9: +35:19 - let mut _31: (); // in scope 0 at $DIR/reference_prop.rs:+35:16: +35:18 + let _30: (); // in scope 0 at $DIR/reference_prop.rs:+35:9: +35:18 + let mut _31: *mut &usize; // in scope 0 at $DIR/reference_prop.rs:+35:16: +35:17 let _32: (); // in scope 0 at $DIR/reference_prop.rs:+39:5: +44:6 let _33: usize; // in scope 0 at $DIR/reference_prop.rs:+40:13: +40:14 let _36: (); // in scope 0 at $DIR/reference_prop.rs:+43:9: +43:18 @@ -35,16 +35,25 @@ let _48: &T; // in scope 0 at $DIR/reference_prop.rs:+61:13: +61:14 let _50: (); // in scope 0 at $DIR/reference_prop.rs:+63:9: +63:19 let mut _51: (); // in scope 0 at $DIR/reference_prop.rs:+63:16: +63:18 - let _52: &T; // in scope 0 at $DIR/reference_prop.rs:+68:13: +68:14 - let mut _53: &T; // in scope 0 at $DIR/reference_prop.rs:+69:20: +69:28 - let _54: &T; // in scope 0 at $DIR/reference_prop.rs:+69:20: +69:28 - let _56: (); // in scope 0 at $DIR/reference_prop.rs:+71:9: +71:19 - let mut _57: (); // in scope 0 at $DIR/reference_prop.rs:+71:16: +71:18 + let _52: (); // in scope 0 at $DIR/reference_prop.rs:+67:5: +72:6 + let _53: &T; // in scope 0 at $DIR/reference_prop.rs:+68:13: +68:14 + let mut _54: &T; // in scope 0 at $DIR/reference_prop.rs:+69:20: +69:28 + let _55: &T; // in scope 0 at $DIR/reference_prop.rs:+69:20: +69:28 + let _57: (); // in scope 0 at $DIR/reference_prop.rs:+71:9: +71:19 + let mut _58: (); // in scope 0 at $DIR/reference_prop.rs:+71:16: +71:18 + let _59: (); // in scope 0 at $DIR/reference_prop.rs:+75:5: +81:6 + let _60: usize; // in scope 0 at $DIR/reference_prop.rs:+76:13: +76:14 + let _64: (); // in scope 0 at $DIR/reference_prop.rs:+80:9: +80:19 + let mut _65: (); // in scope 0 at $DIR/reference_prop.rs:+80:16: +80:18 + let _66: usize; // in scope 0 at $DIR/reference_prop.rs:+85:13: +85:14 + let _70: (); // in scope 0 at $DIR/reference_prop.rs:+89:9: +89:19 + let mut _71: (); // in scope 0 at $DIR/reference_prop.rs:+89:16: +89:18 scope 1 { debug a => _4; // in scope 1 at $DIR/reference_prop.rs:+3:13: +3:14 let _5: &usize; // in scope 1 at $DIR/reference_prop.rs:+4:13: +4:14 scope 2 { - debug b => _5; // in scope 2 at $DIR/reference_prop.rs:+4:13: +4:14 +- debug b => _5; // in scope 2 at $DIR/reference_prop.rs:+4:13: +4:14 ++ debug b => &_4; // in scope 2 at $DIR/reference_prop.rs:+4:13: +4:14 let _6: usize; // in scope 2 at $DIR/reference_prop.rs:+5:13: +5:14 scope 3 { debug c => _6; // in scope 3 at $DIR/reference_prop.rs:+5:13: +5:14 @@ -86,7 +95,7 @@ let mut _27: &usize; // in scope 12 at $DIR/reference_prop.rs:+32:13: +32:18 scope 13 { debug b => _27; // in scope 13 at $DIR/reference_prop.rs:+32:13: +32:18 - let _28: &mut &usize; // in scope 13 at $DIR/reference_prop.rs:+33:13: +33:14 + let _28: *mut &usize; // in scope 13 at $DIR/reference_prop.rs:+33:13: +33:14 scope 14 { debug d => _28; // in scope 14 at $DIR/reference_prop.rs:+33:13: +33:14 let _29: usize; // in scope 14 at $DIR/reference_prop.rs:+34:13: +34:14 @@ -131,17 +140,52 @@ } } scope 25 { - debug a => _48; // in scope 25 at $DIR/reference_prop.rs:+61:13: +61:14 +- debug a => _48; // in scope 25 at $DIR/reference_prop.rs:+61:13: +61:14 ++ debug a => _1; // in scope 25 at $DIR/reference_prop.rs:+61:13: +61:14 let _49: T; // in scope 25 at $DIR/reference_prop.rs:+62:13: +62:14 scope 26 { debug b => _49; // in scope 26 at $DIR/reference_prop.rs:+62:13: +62:14 } } scope 27 { - debug a => _52; // in scope 27 at $DIR/reference_prop.rs:+68:13: +68:14 - let _55: T; // in scope 27 at $DIR/reference_prop.rs:+70:13: +70:14 + debug a => _53; // in scope 27 at $DIR/reference_prop.rs:+68:13: +68:14 + let _56: T; // in scope 27 at $DIR/reference_prop.rs:+70:13: +70:14 scope 28 { - debug b => _55; // in scope 28 at $DIR/reference_prop.rs:+70:13: +70:14 + debug b => _56; // in scope 28 at $DIR/reference_prop.rs:+70:13: +70:14 + } + } + scope 29 { + debug a => _60; // in scope 29 at $DIR/reference_prop.rs:+76:13: +76:14 + let _61: &usize; // in scope 29 at $DIR/reference_prop.rs:+77:13: +77:14 + scope 30 { +- debug b => _61; // in scope 30 at $DIR/reference_prop.rs:+77:13: +77:14 ++ debug b => &_60; // in scope 30 at $DIR/reference_prop.rs:+77:13: +77:14 + let _62: &&usize; // in scope 30 at $DIR/reference_prop.rs:+78:13: +78:14 + scope 31 { +- debug d => _62; // in scope 31 at $DIR/reference_prop.rs:+78:13: +78:14 ++ debug d => &&_60; // in scope 31 at $DIR/reference_prop.rs:+78:13: +78:14 + let _63: usize; // in scope 31 at $DIR/reference_prop.rs:+79:13: +79:14 + scope 32 { + debug c => _63; // in scope 32 at $DIR/reference_prop.rs:+79:13: +79:14 + } + } + } + } + scope 33 { + debug a => _66; // in scope 33 at $DIR/reference_prop.rs:+85:13: +85:14 + let mut _67: &usize; // in scope 33 at $DIR/reference_prop.rs:+86:13: +86:18 + scope 34 { +- debug b => _67; // in scope 34 at $DIR/reference_prop.rs:+86:13: +86:18 ++ debug b => &_66; // in scope 34 at $DIR/reference_prop.rs:+86:13: +86:18 + let _68: &mut &usize; // in scope 34 at $DIR/reference_prop.rs:+87:13: +87:14 + scope 35 { +- debug d => _68; // in scope 35 at $DIR/reference_prop.rs:+87:13: +87:14 ++ debug d => &&_66; // in scope 35 at $DIR/reference_prop.rs:+87:13: +87:14 + let _69: usize; // in scope 35 at $DIR/reference_prop.rs:+88:13: +88:14 + scope 36 { + debug c => _69; // in scope 36 at $DIR/reference_prop.rs:+88:13: +88:14 + } + } } } @@ -149,8 +193,8 @@ - StorageLive(_3); // scope 0 at $DIR/reference_prop.rs:+2:5: +7:6 StorageLive(_4); // scope 0 at $DIR/reference_prop.rs:+3:13: +3:14 _4 = const 5_usize; // scope 0 at $DIR/reference_prop.rs:+3:17: +3:24 - StorageLive(_5); // scope 1 at $DIR/reference_prop.rs:+4:13: +4:14 - _5 = &_4; // scope 1 at $DIR/reference_prop.rs:+4:17: +4:19 +- StorageLive(_5); // scope 1 at $DIR/reference_prop.rs:+4:13: +4:14 +- _5 = &_4; // scope 1 at $DIR/reference_prop.rs:+4:17: +4:19 StorageLive(_6); // scope 2 at $DIR/reference_prop.rs:+5:13: +5:14 - _6 = (*_5); // scope 2 at $DIR/reference_prop.rs:+5:17: +5:19 + _6 = _4; // scope 2 at $DIR/reference_prop.rs:+5:17: +5:19 @@ -168,7 +212,7 @@ StorageDead(_7); // scope 3 at $DIR/reference_prop.rs:+6:19: +6:20 - _3 = const (); // scope 0 at $DIR/reference_prop.rs:+2:5: +7:6 StorageDead(_6); // scope 2 at $DIR/reference_prop.rs:+7:5: +7:6 - StorageDead(_5); // scope 1 at $DIR/reference_prop.rs:+7:5: +7:6 +- StorageDead(_5); // scope 1 at $DIR/reference_prop.rs:+7:5: +7:6 StorageDead(_4); // scope 0 at $DIR/reference_prop.rs:+7:5: +7:6 - StorageDead(_3); // scope 0 at $DIR/reference_prop.rs:+7:5: +7:6 - StorageLive(_9); // scope 0 at $DIR/reference_prop.rs:+10:5: +18:6 @@ -215,18 +259,18 @@ _21 = &_20; // scope 9 at $DIR/reference_prop.rs:+24:17: +24:19 StorageLive(_22); // scope 10 at $DIR/reference_prop.rs:+25:13: +25:14 _22 = (*_20); // scope 10 at $DIR/reference_prop.rs:+25:17: +25:19 - StorageLive(_23); // scope 11 at $DIR/reference_prop.rs:+26:9: +26:19 - StorageLive(_24); // scope 11 at $DIR/reference_prop.rs:+26:16: +26:18 - _24 = (); // scope 11 at $DIR/reference_prop.rs:+26:16: +26:18 - _23 = opaque::<()>(move _24) -> bb3; // scope 11 at $DIR/reference_prop.rs:+26:9: +26:19 + StorageLive(_23); // scope 11 at $DIR/reference_prop.rs:+26:9: +26:18 + StorageLive(_24); // scope 11 at $DIR/reference_prop.rs:+26:16: +26:17 + _24 = _21; // scope 11 at $DIR/reference_prop.rs:+26:16: +26:17 + _23 = opaque::<&&usize>(move _24) -> bb3; // scope 11 at $DIR/reference_prop.rs:+26:9: +26:18 // mir::Constant // + span: $DIR/reference_prop.rs:36:9: 36:15 - // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + // + literal: Const { ty: fn(&&usize) {opaque::<&&usize>}, val: Value(<ZST>) } } bb3: { - StorageDead(_24); // scope 11 at $DIR/reference_prop.rs:+26:18: +26:19 - StorageDead(_23); // scope 11 at $DIR/reference_prop.rs:+26:19: +26:20 + StorageDead(_24); // scope 11 at $DIR/reference_prop.rs:+26:17: +26:18 + StorageDead(_23); // scope 11 at $DIR/reference_prop.rs:+26:18: +26:19 - _18 = const (); // scope 0 at $DIR/reference_prop.rs:+21:5: +27:6 StorageDead(_22); // scope 10 at $DIR/reference_prop.rs:+27:5: +27:6 StorageDead(_21); // scope 9 at $DIR/reference_prop.rs:+27:5: +27:6 @@ -239,21 +283,21 @@ StorageLive(_27); // scope 12 at $DIR/reference_prop.rs:+32:13: +32:18 _27 = &_26; // scope 12 at $DIR/reference_prop.rs:+32:21: +32:23 StorageLive(_28); // scope 13 at $DIR/reference_prop.rs:+33:13: +33:14 - _28 = &mut _27; // scope 13 at $DIR/reference_prop.rs:+33:17: +33:23 + _28 = &raw mut _27; // scope 13 at $DIR/reference_prop.rs:+33:17: +33:27 StorageLive(_29); // scope 14 at $DIR/reference_prop.rs:+34:13: +34:14 _29 = (*_27); // scope 14 at $DIR/reference_prop.rs:+34:17: +34:19 - StorageLive(_30); // scope 15 at $DIR/reference_prop.rs:+35:9: +35:19 - StorageLive(_31); // scope 15 at $DIR/reference_prop.rs:+35:16: +35:18 - _31 = (); // scope 15 at $DIR/reference_prop.rs:+35:16: +35:18 - _30 = opaque::<()>(move _31) -> bb4; // scope 15 at $DIR/reference_prop.rs:+35:9: +35:19 + StorageLive(_30); // scope 15 at $DIR/reference_prop.rs:+35:9: +35:18 + StorageLive(_31); // scope 15 at $DIR/reference_prop.rs:+35:16: +35:17 + _31 = _28; // scope 15 at $DIR/reference_prop.rs:+35:16: +35:17 + _30 = opaque::<*mut &usize>(move _31) -> bb4; // scope 15 at $DIR/reference_prop.rs:+35:9: +35:18 // mir::Constant // + span: $DIR/reference_prop.rs:45:9: 45:15 - // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + // + literal: Const { ty: fn(*mut &usize) {opaque::<*mut &usize>}, val: Value(<ZST>) } } bb4: { - StorageDead(_31); // scope 15 at $DIR/reference_prop.rs:+35:18: +35:19 - StorageDead(_30); // scope 15 at $DIR/reference_prop.rs:+35:19: +35:20 + StorageDead(_31); // scope 15 at $DIR/reference_prop.rs:+35:17: +35:18 + StorageDead(_30); // scope 15 at $DIR/reference_prop.rs:+35:18: +35:19 - _25 = const (); // scope 0 at $DIR/reference_prop.rs:+30:5: +36:6 StorageDead(_29); // scope 14 at $DIR/reference_prop.rs:+36:5: +36:6 StorageDead(_28); // scope 13 at $DIR/reference_prop.rs:+36:5: +36:6 @@ -321,8 +365,8 @@ StorageDead(_39); // scope 0 at $DIR/reference_prop.rs:+57:5: +57:6 - StorageDead(_38); // scope 0 at $DIR/reference_prop.rs:+57:5: +57:6 - StorageLive(_47); // scope 0 at $DIR/reference_prop.rs:+60:5: +64:6 - StorageLive(_48); // scope 0 at $DIR/reference_prop.rs:+61:13: +61:14 - _48 = &(*_1); // scope 0 at $DIR/reference_prop.rs:+61:17: +61:25 +- StorageLive(_48); // scope 0 at $DIR/reference_prop.rs:+61:13: +61:14 +- _48 = &(*_1); // scope 0 at $DIR/reference_prop.rs:+61:17: +61:25 StorageLive(_49); // scope 25 at $DIR/reference_prop.rs:+62:13: +62:14 - _49 = (*_48); // scope 25 at $DIR/reference_prop.rs:+62:17: +62:19 + _49 = (*_1); // scope 25 at $DIR/reference_prop.rs:+62:17: +62:19 @@ -340,36 +384,92 @@ StorageDead(_50); // scope 26 at $DIR/reference_prop.rs:+63:19: +63:20 - _47 = const (); // scope 0 at $DIR/reference_prop.rs:+60:5: +64:6 StorageDead(_49); // scope 25 at $DIR/reference_prop.rs:+64:5: +64:6 - StorageDead(_48); // scope 0 at $DIR/reference_prop.rs:+64:5: +64:6 +- StorageDead(_48); // scope 0 at $DIR/reference_prop.rs:+64:5: +64:6 - StorageDead(_47); // scope 0 at $DIR/reference_prop.rs:+64:5: +64:6 - StorageLive(_52); // scope 0 at $DIR/reference_prop.rs:+68:13: +68:14 - _52 = &(*_2); // scope 0 at $DIR/reference_prop.rs:+68:17: +68:27 - StorageLive(_53); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:28 -- StorageLive(_54); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:28 -- _54 = &(*_1); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:28 -- _53 = &(*_54); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:28 -+ _53 = &(*_1); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:28 - _2 = move _53; // scope 27 at $DIR/reference_prop.rs:+69:9: +69:28 - StorageDead(_53); // scope 27 at $DIR/reference_prop.rs:+69:27: +69:28 -- StorageDead(_54); // scope 27 at $DIR/reference_prop.rs:+69:28: +69:29 - StorageLive(_55); // scope 27 at $DIR/reference_prop.rs:+70:13: +70:14 - _55 = (*_52); // scope 27 at $DIR/reference_prop.rs:+70:17: +70:19 - StorageLive(_56); // scope 28 at $DIR/reference_prop.rs:+71:9: +71:19 - StorageLive(_57); // scope 28 at $DIR/reference_prop.rs:+71:16: +71:18 - _57 = (); // scope 28 at $DIR/reference_prop.rs:+71:16: +71:18 - _56 = opaque::<()>(move _57) -> bb8; // scope 28 at $DIR/reference_prop.rs:+71:9: +71:19 +- StorageLive(_52); // scope 0 at $DIR/reference_prop.rs:+67:5: +72:6 + StorageLive(_53); // scope 0 at $DIR/reference_prop.rs:+68:13: +68:14 + _53 = &(*_2); // scope 0 at $DIR/reference_prop.rs:+68:17: +68:27 + StorageLive(_54); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:28 +- StorageLive(_55); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:28 +- _55 = &(*_1); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:28 +- _54 = &(*_55); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:28 ++ _54 = &(*_1); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:28 + _2 = move _54; // scope 27 at $DIR/reference_prop.rs:+69:9: +69:28 + StorageDead(_54); // scope 27 at $DIR/reference_prop.rs:+69:27: +69:28 +- StorageDead(_55); // scope 27 at $DIR/reference_prop.rs:+69:28: +69:29 + StorageLive(_56); // scope 27 at $DIR/reference_prop.rs:+70:13: +70:14 + _56 = (*_53); // scope 27 at $DIR/reference_prop.rs:+70:17: +70:19 + StorageLive(_57); // scope 28 at $DIR/reference_prop.rs:+71:9: +71:19 + StorageLive(_58); // scope 28 at $DIR/reference_prop.rs:+71:16: +71:18 + _58 = (); // scope 28 at $DIR/reference_prop.rs:+71:16: +71:18 + _57 = opaque::<()>(move _58) -> bb8; // scope 28 at $DIR/reference_prop.rs:+71:9: +71:19 // mir::Constant // + span: $DIR/reference_prop.rs:81:9: 81:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } bb8: { - StorageDead(_57); // scope 28 at $DIR/reference_prop.rs:+71:18: +71:19 - StorageDead(_56); // scope 28 at $DIR/reference_prop.rs:+71:19: +71:20 - _0 = const (); // scope 0 at $DIR/reference_prop.rs:+67:5: +72:6 - StorageDead(_55); // scope 27 at $DIR/reference_prop.rs:+72:5: +72:6 - StorageDead(_52); // scope 0 at $DIR/reference_prop.rs:+72:5: +72:6 - return; // scope 0 at $DIR/reference_prop.rs:+73:2: +73:2 + StorageDead(_58); // scope 28 at $DIR/reference_prop.rs:+71:18: +71:19 + StorageDead(_57); // scope 28 at $DIR/reference_prop.rs:+71:19: +71:20 +- _52 = const (); // scope 0 at $DIR/reference_prop.rs:+67:5: +72:6 + StorageDead(_56); // scope 27 at $DIR/reference_prop.rs:+72:5: +72:6 + StorageDead(_53); // scope 0 at $DIR/reference_prop.rs:+72:5: +72:6 +- StorageDead(_52); // scope 0 at $DIR/reference_prop.rs:+72:5: +72:6 +- StorageLive(_59); // scope 0 at $DIR/reference_prop.rs:+75:5: +81:6 + StorageLive(_60); // scope 0 at $DIR/reference_prop.rs:+76:13: +76:14 + _60 = const 5_usize; // scope 0 at $DIR/reference_prop.rs:+76:17: +76:24 +- StorageLive(_61); // scope 29 at $DIR/reference_prop.rs:+77:13: +77:14 +- _61 = &_60; // scope 29 at $DIR/reference_prop.rs:+77:17: +77:19 +- StorageLive(_62); // scope 30 at $DIR/reference_prop.rs:+78:13: +78:14 +- _62 = &_61; // scope 30 at $DIR/reference_prop.rs:+78:17: +78:19 + StorageLive(_63); // scope 31 at $DIR/reference_prop.rs:+79:13: +79:14 +- _63 = (*_61); // scope 31 at $DIR/reference_prop.rs:+79:17: +79:19 ++ _63 = _60; // scope 31 at $DIR/reference_prop.rs:+79:17: +79:19 + StorageLive(_64); // scope 32 at $DIR/reference_prop.rs:+80:9: +80:19 + StorageLive(_65); // scope 32 at $DIR/reference_prop.rs:+80:16: +80:18 + _65 = (); // scope 32 at $DIR/reference_prop.rs:+80:16: +80:18 + _64 = opaque::<()>(move _65) -> bb9; // scope 32 at $DIR/reference_prop.rs:+80:9: +80:19 + // mir::Constant + // + span: $DIR/reference_prop.rs:90:9: 90:15 + // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + } + + bb9: { + StorageDead(_65); // scope 32 at $DIR/reference_prop.rs:+80:18: +80:19 + StorageDead(_64); // scope 32 at $DIR/reference_prop.rs:+80:19: +80:20 +- _59 = const (); // scope 0 at $DIR/reference_prop.rs:+75:5: +81:6 + StorageDead(_63); // scope 31 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageDead(_62); // scope 30 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageDead(_61); // scope 29 at $DIR/reference_prop.rs:+81:5: +81:6 + StorageDead(_60); // scope 0 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageDead(_59); // scope 0 at $DIR/reference_prop.rs:+81:5: +81:6 + StorageLive(_66); // scope 0 at $DIR/reference_prop.rs:+85:13: +85:14 + _66 = const 5_usize; // scope 0 at $DIR/reference_prop.rs:+85:17: +85:24 +- StorageLive(_67); // scope 33 at $DIR/reference_prop.rs:+86:13: +86:18 +- _67 = &_66; // scope 33 at $DIR/reference_prop.rs:+86:21: +86:23 +- StorageLive(_68); // scope 34 at $DIR/reference_prop.rs:+87:13: +87:14 +- _68 = &mut _67; // scope 34 at $DIR/reference_prop.rs:+87:17: +87:23 + StorageLive(_69); // scope 35 at $DIR/reference_prop.rs:+88:13: +88:14 +- _69 = (*_67); // scope 35 at $DIR/reference_prop.rs:+88:17: +88:19 ++ _69 = _66; // scope 35 at $DIR/reference_prop.rs:+88:17: +88:19 + StorageLive(_70); // scope 36 at $DIR/reference_prop.rs:+89:9: +89:19 + StorageLive(_71); // scope 36 at $DIR/reference_prop.rs:+89:16: +89:18 + _71 = (); // scope 36 at $DIR/reference_prop.rs:+89:16: +89:18 + _70 = opaque::<()>(move _71) -> bb10; // scope 36 at $DIR/reference_prop.rs:+89:9: +89:19 + // mir::Constant + // + span: $DIR/reference_prop.rs:99:9: 99:15 + // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + } + + bb10: { + StorageDead(_71); // scope 36 at $DIR/reference_prop.rs:+89:18: +89:19 + StorageDead(_70); // scope 36 at $DIR/reference_prop.rs:+89:19: +89:20 + _0 = const (); // scope 0 at $DIR/reference_prop.rs:+84:5: +90:6 + StorageDead(_69); // scope 35 at $DIR/reference_prop.rs:+90:5: +90:6 +- StorageDead(_68); // scope 34 at $DIR/reference_prop.rs:+90:5: +90:6 +- StorageDead(_67); // scope 33 at $DIR/reference_prop.rs:+90:5: +90:6 + StorageDead(_66); // scope 0 at $DIR/reference_prop.rs:+90:5: +90:6 + return; // scope 0 at $DIR/reference_prop.rs:+91:2: +91:2 } } diff --git a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff index 712727915d0..ddeb04e50c7 100644 --- a/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.reference_propagation_const_ptr.ReferencePropagation.diff @@ -13,11 +13,11 @@ let _15: (); // in scope 0 at $DIR/reference_prop.rs:+17:9: +17:19 let mut _16: (); // in scope 0 at $DIR/reference_prop.rs:+17:16: +17:18 let _17: (); // in scope 0 at $DIR/reference_prop.rs:+21:5: +27:6 - let _22: (); // in scope 0 at $DIR/reference_prop.rs:+26:9: +26:19 - let mut _23: (); // in scope 0 at $DIR/reference_prop.rs:+26:16: +26:18 + let _22: (); // in scope 0 at $DIR/reference_prop.rs:+26:9: +26:18 + let mut _23: &*const usize; // in scope 0 at $DIR/reference_prop.rs:+26:16: +26:17 let _24: (); // in scope 0 at $DIR/reference_prop.rs:+30:5: +36:6 - let _29: (); // in scope 0 at $DIR/reference_prop.rs:+35:9: +35:19 - let mut _30: (); // in scope 0 at $DIR/reference_prop.rs:+35:16: +35:18 + let _29: (); // in scope 0 at $DIR/reference_prop.rs:+35:9: +35:18 + let mut _30: *mut *const usize; // in scope 0 at $DIR/reference_prop.rs:+35:16: +35:17 let _31: (); // in scope 0 at $DIR/reference_prop.rs:+39:5: +44:6 let _35: (); // in scope 0 at $DIR/reference_prop.rs:+43:9: +43:18 let mut _36: *const usize; // in scope 0 at $DIR/reference_prop.rs:+43:16: +43:17 @@ -31,15 +31,22 @@ let mut _53: *const T; // in scope 0 at $DIR/reference_prop.rs:+69:20: +69:38 let _55: (); // in scope 0 at $DIR/reference_prop.rs:+71:9: +71:19 let mut _56: (); // in scope 0 at $DIR/reference_prop.rs:+71:16: +71:18 - let _61: (); // in scope 0 at $DIR/reference_prop.rs:+80:9: +80:19 - let mut _62: (); // in scope 0 at $DIR/reference_prop.rs:+80:16: +80:18 + let _57: (); // in scope 0 at $DIR/reference_prop.rs:+75:5: +81:6 + let _62: (); // in scope 0 at $DIR/reference_prop.rs:+80:9: +80:19 + let mut _63: (); // in scope 0 at $DIR/reference_prop.rs:+80:16: +80:18 + let _64: (); // in scope 0 at $DIR/reference_prop.rs:+84:5: +90:6 + let _69: (); // in scope 0 at $DIR/reference_prop.rs:+89:9: +89:19 + let mut _70: (); // in scope 0 at $DIR/reference_prop.rs:+89:16: +89:18 + let _75: (); // in scope 0 at $DIR/reference_prop.rs:+98:9: +98:19 + let mut _76: (); // in scope 0 at $DIR/reference_prop.rs:+98:16: +98:18 scope 1 { let _4: usize; // in scope 1 at $DIR/reference_prop.rs:+3:13: +3:14 scope 2 { debug a => _4; // in scope 2 at $DIR/reference_prop.rs:+3:13: +3:14 let _5: *const usize; // in scope 2 at $DIR/reference_prop.rs:+4:13: +4:14 scope 3 { - debug b => _5; // in scope 3 at $DIR/reference_prop.rs:+4:13: +4:14 +- debug b => _5; // in scope 3 at $DIR/reference_prop.rs:+4:13: +4:14 ++ debug b => &_4; // in scope 3 at $DIR/reference_prop.rs:+4:13: +4:14 let _6: usize; // in scope 3 at $DIR/reference_prop.rs:+5:13: +5:14 scope 4 { debug c => _6; // in scope 4 at $DIR/reference_prop.rs:+5:13: +5:14 @@ -90,7 +97,7 @@ let mut _26: *const usize; // in scope 16 at $DIR/reference_prop.rs:+32:13: +32:18 scope 17 { debug b => _26; // in scope 17 at $DIR/reference_prop.rs:+32:13: +32:18 - let _27: &mut *const usize; // in scope 17 at $DIR/reference_prop.rs:+33:13: +33:14 + let _27: *mut *const usize; // in scope 17 at $DIR/reference_prop.rs:+33:13: +33:14 scope 18 { debug d => _27; // in scope 18 at $DIR/reference_prop.rs:+33:13: +33:14 let _28: usize; // in scope 18 at $DIR/reference_prop.rs:+34:13: +34:14 @@ -144,7 +151,8 @@ scope 31 { let _47: *const T; // in scope 31 at $DIR/reference_prop.rs:+61:13: +61:14 scope 32 { - debug a => _47; // in scope 32 at $DIR/reference_prop.rs:+61:13: +61:14 +- debug a => _47; // in scope 32 at $DIR/reference_prop.rs:+61:13: +61:14 ++ debug a => _1; // in scope 32 at $DIR/reference_prop.rs:+61:13: +61:14 let _48: T; // in scope 32 at $DIR/reference_prop.rs:+62:13: +62:14 scope 33 { debug b => _48; // in scope 33 at $DIR/reference_prop.rs:+62:13: +62:14 @@ -162,18 +170,60 @@ } } scope 37 { - let _57: usize; // in scope 37 at $DIR/reference_prop.rs:+76:13: +76:14 + let _58: usize; // in scope 37 at $DIR/reference_prop.rs:+76:13: +76:14 scope 38 { - debug a => _57; // in scope 38 at $DIR/reference_prop.rs:+76:13: +76:14 - let _58: *const usize; // in scope 38 at $DIR/reference_prop.rs:+77:13: +77:14 + debug a => _58; // in scope 38 at $DIR/reference_prop.rs:+76:13: +76:14 + let _59: *const usize; // in scope 38 at $DIR/reference_prop.rs:+77:13: +77:14 scope 39 { - debug b => _58; // in scope 39 at $DIR/reference_prop.rs:+77:13: +77:14 - let _59: *const usize; // in scope 39 at $DIR/reference_prop.rs:+78:13: +78:14 +- debug b => _59; // in scope 39 at $DIR/reference_prop.rs:+77:13: +77:14 ++ debug b => &_58; // in scope 39 at $DIR/reference_prop.rs:+77:13: +77:14 + let _60: *const usize; // in scope 39 at $DIR/reference_prop.rs:+78:13: +78:14 scope 40 { - debug c => _59; // in scope 40 at $DIR/reference_prop.rs:+78:13: +78:14 - let _60: usize; // in scope 40 at $DIR/reference_prop.rs:+79:13: +79:14 +- debug c => _60; // in scope 40 at $DIR/reference_prop.rs:+78:13: +78:14 ++ debug c => &_58; // in scope 40 at $DIR/reference_prop.rs:+78:13: +78:14 + let _61: usize; // in scope 40 at $DIR/reference_prop.rs:+79:13: +79:14 scope 41 { - debug e => _60; // in scope 41 at $DIR/reference_prop.rs:+79:13: +79:14 + debug e => _61; // in scope 41 at $DIR/reference_prop.rs:+79:13: +79:14 + } + } + } + } + } + scope 42 { + let _65: usize; // in scope 42 at $DIR/reference_prop.rs:+85:13: +85:14 + scope 43 { + debug a => _65; // in scope 43 at $DIR/reference_prop.rs:+85:13: +85:14 + let _66: *const usize; // in scope 43 at $DIR/reference_prop.rs:+86:13: +86:14 + scope 44 { +- debug b => _66; // in scope 44 at $DIR/reference_prop.rs:+86:13: +86:14 ++ debug b => &_65; // in scope 44 at $DIR/reference_prop.rs:+86:13: +86:14 + let _67: &*const usize; // in scope 44 at $DIR/reference_prop.rs:+87:13: +87:14 + scope 45 { +- debug d => _67; // in scope 45 at $DIR/reference_prop.rs:+87:13: +87:14 ++ debug d => &&_65; // in scope 45 at $DIR/reference_prop.rs:+87:13: +87:14 + let _68: usize; // in scope 45 at $DIR/reference_prop.rs:+88:13: +88:14 + scope 46 { + debug c => _68; // in scope 46 at $DIR/reference_prop.rs:+88:13: +88:14 + } + } + } + } + } + scope 47 { + let _71: usize; // in scope 47 at $DIR/reference_prop.rs:+94:13: +94:14 + scope 48 { + debug a => _71; // in scope 48 at $DIR/reference_prop.rs:+94:13: +94:14 + let mut _72: *const usize; // in scope 48 at $DIR/reference_prop.rs:+95:13: +95:18 + scope 49 { +- debug b => _72; // in scope 49 at $DIR/reference_prop.rs:+95:13: +95:18 ++ debug b => &_71; // in scope 49 at $DIR/reference_prop.rs:+95:13: +95:18 + let _73: &mut *const usize; // in scope 49 at $DIR/reference_prop.rs:+96:13: +96:14 + scope 50 { +- debug d => _73; // in scope 50 at $DIR/reference_prop.rs:+96:13: +96:14 ++ debug d => &&_71; // in scope 50 at $DIR/reference_prop.rs:+96:13: +96:14 + let _74: usize; // in scope 50 at $DIR/reference_prop.rs:+97:13: +97:14 + scope 51 { + debug c => _74; // in scope 51 at $DIR/reference_prop.rs:+97:13: +97:14 } } } @@ -184,8 +234,8 @@ - StorageLive(_3); // scope 0 at $DIR/reference_prop.rs:+2:5: +7:6 StorageLive(_4); // scope 1 at $DIR/reference_prop.rs:+3:13: +3:14 _4 = const 5_usize; // scope 1 at $DIR/reference_prop.rs:+3:17: +3:24 - StorageLive(_5); // scope 2 at $DIR/reference_prop.rs:+4:13: +4:14 - _5 = &raw const _4; // scope 2 at $DIR/reference_prop.rs:+4:17: +4:29 +- StorageLive(_5); // scope 2 at $DIR/reference_prop.rs:+4:13: +4:14 +- _5 = &raw const _4; // scope 2 at $DIR/reference_prop.rs:+4:17: +4:29 StorageLive(_6); // scope 3 at $DIR/reference_prop.rs:+5:13: +5:14 - _6 = (*_5); // scope 3 at $DIR/reference_prop.rs:+5:17: +5:19 + _6 = _4; // scope 3 at $DIR/reference_prop.rs:+5:17: +5:19 @@ -194,7 +244,7 @@ _8 = (); // scope 4 at $DIR/reference_prop.rs:+6:16: +6:18 _7 = opaque::<()>(move _8) -> bb1; // scope 4 at $DIR/reference_prop.rs:+6:9: +6:19 // mir::Constant - // + span: $DIR/reference_prop.rs:166:9: 166:15 + // + span: $DIR/reference_prop.rs:202:9: 202:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } @@ -203,7 +253,7 @@ StorageDead(_7); // scope 4 at $DIR/reference_prop.rs:+6:19: +6:20 - _3 = const (); // scope 1 at $DIR/reference_prop.rs:+2:5: +7:6 StorageDead(_6); // scope 3 at $DIR/reference_prop.rs:+7:5: +7:6 - StorageDead(_5); // scope 2 at $DIR/reference_prop.rs:+7:5: +7:6 +- StorageDead(_5); // scope 2 at $DIR/reference_prop.rs:+7:5: +7:6 StorageDead(_4); // scope 1 at $DIR/reference_prop.rs:+7:5: +7:6 - StorageDead(_3); // scope 0 at $DIR/reference_prop.rs:+7:5: +7:6 - StorageLive(_9); // scope 0 at $DIR/reference_prop.rs:+10:5: +18:6 @@ -224,7 +274,7 @@ _16 = (); // scope 9 at $DIR/reference_prop.rs:+17:16: +17:18 _15 = opaque::<()>(move _16) -> bb2; // scope 9 at $DIR/reference_prop.rs:+17:9: +17:19 // mir::Constant - // + span: $DIR/reference_prop.rs:177:9: 177:15 + // + span: $DIR/reference_prop.rs:213:9: 213:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } @@ -246,18 +296,18 @@ _20 = &_19; // scope 12 at $DIR/reference_prop.rs:+24:17: +24:19 StorageLive(_21); // scope 13 at $DIR/reference_prop.rs:+25:13: +25:14 _21 = (*_19); // scope 13 at $DIR/reference_prop.rs:+25:17: +25:19 - StorageLive(_22); // scope 14 at $DIR/reference_prop.rs:+26:9: +26:19 - StorageLive(_23); // scope 14 at $DIR/reference_prop.rs:+26:16: +26:18 - _23 = (); // scope 14 at $DIR/reference_prop.rs:+26:16: +26:18 - _22 = opaque::<()>(move _23) -> bb3; // scope 14 at $DIR/reference_prop.rs:+26:9: +26:19 + StorageLive(_22); // scope 14 at $DIR/reference_prop.rs:+26:9: +26:18 + StorageLive(_23); // scope 14 at $DIR/reference_prop.rs:+26:16: +26:17 + _23 = _20; // scope 14 at $DIR/reference_prop.rs:+26:16: +26:17 + _22 = opaque::<&*const usize>(move _23) -> bb3; // scope 14 at $DIR/reference_prop.rs:+26:9: +26:18 // mir::Constant - // + span: $DIR/reference_prop.rs:186:9: 186:15 - // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + // + span: $DIR/reference_prop.rs:222:9: 222:15 + // + literal: Const { ty: fn(&*const usize) {opaque::<&*const usize>}, val: Value(<ZST>) } } bb3: { - StorageDead(_23); // scope 14 at $DIR/reference_prop.rs:+26:18: +26:19 - StorageDead(_22); // scope 14 at $DIR/reference_prop.rs:+26:19: +26:20 + StorageDead(_23); // scope 14 at $DIR/reference_prop.rs:+26:17: +26:18 + StorageDead(_22); // scope 14 at $DIR/reference_prop.rs:+26:18: +26:19 - _17 = const (); // scope 10 at $DIR/reference_prop.rs:+21:5: +27:6 StorageDead(_21); // scope 13 at $DIR/reference_prop.rs:+27:5: +27:6 StorageDead(_20); // scope 12 at $DIR/reference_prop.rs:+27:5: +27:6 @@ -270,21 +320,21 @@ StorageLive(_26); // scope 16 at $DIR/reference_prop.rs:+32:13: +32:18 _26 = &raw const _25; // scope 16 at $DIR/reference_prop.rs:+32:21: +32:33 StorageLive(_27); // scope 17 at $DIR/reference_prop.rs:+33:13: +33:14 - _27 = &mut _26; // scope 17 at $DIR/reference_prop.rs:+33:17: +33:23 + _27 = &raw mut _26; // scope 17 at $DIR/reference_prop.rs:+33:17: +33:27 StorageLive(_28); // scope 18 at $DIR/reference_prop.rs:+34:13: +34:14 _28 = (*_26); // scope 18 at $DIR/reference_prop.rs:+34:17: +34:19 - StorageLive(_29); // scope 19 at $DIR/reference_prop.rs:+35:9: +35:19 - StorageLive(_30); // scope 19 at $DIR/reference_prop.rs:+35:16: +35:18 - _30 = (); // scope 19 at $DIR/reference_prop.rs:+35:16: +35:18 - _29 = opaque::<()>(move _30) -> bb4; // scope 19 at $DIR/reference_prop.rs:+35:9: +35:19 + StorageLive(_29); // scope 19 at $DIR/reference_prop.rs:+35:9: +35:18 + StorageLive(_30); // scope 19 at $DIR/reference_prop.rs:+35:16: +35:17 + _30 = _27; // scope 19 at $DIR/reference_prop.rs:+35:16: +35:17 + _29 = opaque::<*mut *const usize>(move _30) -> bb4; // scope 19 at $DIR/reference_prop.rs:+35:9: +35:18 // mir::Constant - // + span: $DIR/reference_prop.rs:195:9: 195:15 - // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + // + span: $DIR/reference_prop.rs:231:9: 231:15 + // + literal: Const { ty: fn(*mut *const usize) {opaque::<*mut *const usize>}, val: Value(<ZST>) } } bb4: { - StorageDead(_30); // scope 19 at $DIR/reference_prop.rs:+35:18: +35:19 - StorageDead(_29); // scope 19 at $DIR/reference_prop.rs:+35:19: +35:20 + StorageDead(_30); // scope 19 at $DIR/reference_prop.rs:+35:17: +35:18 + StorageDead(_29); // scope 19 at $DIR/reference_prop.rs:+35:18: +35:19 - _24 = const (); // scope 15 at $DIR/reference_prop.rs:+30:5: +36:6 StorageDead(_28); // scope 18 at $DIR/reference_prop.rs:+36:5: +36:6 StorageDead(_27); // scope 17 at $DIR/reference_prop.rs:+36:5: +36:6 @@ -304,7 +354,7 @@ _36 = _33; // scope 23 at $DIR/reference_prop.rs:+43:16: +43:17 _35 = opaque::<*const usize>(move _36) -> bb5; // scope 23 at $DIR/reference_prop.rs:+43:9: +43:18 // mir::Constant - // + span: $DIR/reference_prop.rs:203:9: 203:15 + // + span: $DIR/reference_prop.rs:239:9: 239:15 // + literal: Const { ty: fn(*const usize) {opaque::<*const usize>}, val: Value(<ZST>) } } @@ -336,7 +386,7 @@ _45 = _43; // scope 30 at $DIR/reference_prop.rs:+56:16: +56:18 _44 = opaque::<*const usize>(move _45) -> bb6; // scope 30 at $DIR/reference_prop.rs:+56:9: +56:19 // mir::Constant - // + span: $DIR/reference_prop.rs:216:9: 216:15 + // + span: $DIR/reference_prop.rs:252:9: 252:15 // + literal: Const { ty: fn(*const usize) {opaque::<*const usize>}, val: Value(<ZST>) } } @@ -352,8 +402,8 @@ StorageDead(_38); // scope 24 at $DIR/reference_prop.rs:+57:5: +57:6 - StorageDead(_37); // scope 0 at $DIR/reference_prop.rs:+57:5: +57:6 - StorageLive(_46); // scope 0 at $DIR/reference_prop.rs:+60:5: +64:6 - StorageLive(_47); // scope 31 at $DIR/reference_prop.rs:+61:13: +61:14 - _47 = &raw const (*_1); // scope 31 at $DIR/reference_prop.rs:+61:17: +61:35 +- StorageLive(_47); // scope 31 at $DIR/reference_prop.rs:+61:13: +61:14 +- _47 = &raw const (*_1); // scope 31 at $DIR/reference_prop.rs:+61:17: +61:35 StorageLive(_48); // scope 32 at $DIR/reference_prop.rs:+62:13: +62:14 - _48 = (*_47); // scope 32 at $DIR/reference_prop.rs:+62:17: +62:19 + _48 = (*_1); // scope 32 at $DIR/reference_prop.rs:+62:17: +62:19 @@ -362,7 +412,7 @@ _50 = (); // scope 33 at $DIR/reference_prop.rs:+63:16: +63:18 _49 = opaque::<()>(move _50) -> bb7; // scope 33 at $DIR/reference_prop.rs:+63:9: +63:19 // mir::Constant - // + span: $DIR/reference_prop.rs:223:9: 223:15 + // + span: $DIR/reference_prop.rs:259:9: 259:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } @@ -371,7 +421,7 @@ StorageDead(_49); // scope 33 at $DIR/reference_prop.rs:+63:19: +63:20 - _46 = const (); // scope 31 at $DIR/reference_prop.rs:+60:5: +64:6 StorageDead(_48); // scope 32 at $DIR/reference_prop.rs:+64:5: +64:6 - StorageDead(_47); // scope 31 at $DIR/reference_prop.rs:+64:5: +64:6 +- StorageDead(_47); // scope 31 at $DIR/reference_prop.rs:+64:5: +64:6 - StorageDead(_46); // scope 0 at $DIR/reference_prop.rs:+64:5: +64:6 - StorageLive(_51); // scope 0 at $DIR/reference_prop.rs:+67:5: +72:6 StorageLive(_52); // scope 34 at $DIR/reference_prop.rs:+68:13: +68:14 @@ -387,7 +437,7 @@ _56 = (); // scope 36 at $DIR/reference_prop.rs:+71:16: +71:18 _55 = opaque::<()>(move _56) -> bb8; // scope 36 at $DIR/reference_prop.rs:+71:9: +71:19 // mir::Constant - // + span: $DIR/reference_prop.rs:231:9: 231:15 + // + span: $DIR/reference_prop.rs:267:9: 267:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } @@ -398,34 +448,89 @@ StorageDead(_54); // scope 35 at $DIR/reference_prop.rs:+72:5: +72:6 StorageDead(_52); // scope 34 at $DIR/reference_prop.rs:+72:5: +72:6 - StorageDead(_51); // scope 0 at $DIR/reference_prop.rs:+72:5: +72:6 - StorageLive(_57); // scope 37 at $DIR/reference_prop.rs:+76:13: +76:14 - _57 = const 13_usize; // scope 37 at $DIR/reference_prop.rs:+76:17: +76:25 - StorageLive(_58); // scope 38 at $DIR/reference_prop.rs:+77:13: +77:14 - _58 = &raw const _57; // scope 38 at $DIR/reference_prop.rs:+77:17: +77:29 - StorageLive(_59); // scope 39 at $DIR/reference_prop.rs:+78:13: +78:14 -- _59 = &raw const (*_58); // scope 39 at $DIR/reference_prop.rs:+78:17: +78:30 -+ _59 = &raw const _57; // scope 39 at $DIR/reference_prop.rs:+78:17: +78:30 - StorageLive(_60); // scope 40 at $DIR/reference_prop.rs:+79:13: +79:14 -- _60 = (*_59); // scope 40 at $DIR/reference_prop.rs:+79:17: +79:19 -+ _60 = _57; // scope 40 at $DIR/reference_prop.rs:+79:17: +79:19 - StorageLive(_61); // scope 41 at $DIR/reference_prop.rs:+80:9: +80:19 - StorageLive(_62); // scope 41 at $DIR/reference_prop.rs:+80:16: +80:18 - _62 = (); // scope 41 at $DIR/reference_prop.rs:+80:16: +80:18 - _61 = opaque::<()>(move _62) -> bb9; // scope 41 at $DIR/reference_prop.rs:+80:9: +80:19 +- StorageLive(_57); // scope 0 at $DIR/reference_prop.rs:+75:5: +81:6 + StorageLive(_58); // scope 37 at $DIR/reference_prop.rs:+76:13: +76:14 + _58 = const 13_usize; // scope 37 at $DIR/reference_prop.rs:+76:17: +76:25 +- StorageLive(_59); // scope 38 at $DIR/reference_prop.rs:+77:13: +77:14 +- _59 = &raw const _58; // scope 38 at $DIR/reference_prop.rs:+77:17: +77:29 +- StorageLive(_60); // scope 39 at $DIR/reference_prop.rs:+78:13: +78:14 +- _60 = &raw const (*_59); // scope 39 at $DIR/reference_prop.rs:+78:17: +78:30 + StorageLive(_61); // scope 40 at $DIR/reference_prop.rs:+79:13: +79:14 +- _61 = (*_60); // scope 40 at $DIR/reference_prop.rs:+79:17: +79:19 ++ _61 = _58; // scope 40 at $DIR/reference_prop.rs:+79:17: +79:19 + StorageLive(_62); // scope 41 at $DIR/reference_prop.rs:+80:9: +80:19 + StorageLive(_63); // scope 41 at $DIR/reference_prop.rs:+80:16: +80:18 + _63 = (); // scope 41 at $DIR/reference_prop.rs:+80:16: +80:18 + _62 = opaque::<()>(move _63) -> bb9; // scope 41 at $DIR/reference_prop.rs:+80:9: +80:19 // mir::Constant - // + span: $DIR/reference_prop.rs:240:9: 240:15 + // + span: $DIR/reference_prop.rs:276:9: 276:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } bb9: { - StorageDead(_62); // scope 41 at $DIR/reference_prop.rs:+80:18: +80:19 - StorageDead(_61); // scope 41 at $DIR/reference_prop.rs:+80:19: +80:20 - _0 = const (); // scope 37 at $DIR/reference_prop.rs:+75:5: +81:6 - StorageDead(_60); // scope 40 at $DIR/reference_prop.rs:+81:5: +81:6 - StorageDead(_59); // scope 39 at $DIR/reference_prop.rs:+81:5: +81:6 - StorageDead(_58); // scope 38 at $DIR/reference_prop.rs:+81:5: +81:6 - StorageDead(_57); // scope 37 at $DIR/reference_prop.rs:+81:5: +81:6 - return; // scope 0 at $DIR/reference_prop.rs:+82:2: +82:2 + StorageDead(_63); // scope 41 at $DIR/reference_prop.rs:+80:18: +80:19 + StorageDead(_62); // scope 41 at $DIR/reference_prop.rs:+80:19: +80:20 +- _57 = const (); // scope 37 at $DIR/reference_prop.rs:+75:5: +81:6 + StorageDead(_61); // scope 40 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageDead(_60); // scope 39 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageDead(_59); // scope 38 at $DIR/reference_prop.rs:+81:5: +81:6 + StorageDead(_58); // scope 37 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageDead(_57); // scope 0 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageLive(_64); // scope 0 at $DIR/reference_prop.rs:+84:5: +90:6 + StorageLive(_65); // scope 42 at $DIR/reference_prop.rs:+85:13: +85:14 + _65 = const 5_usize; // scope 42 at $DIR/reference_prop.rs:+85:17: +85:24 +- StorageLive(_66); // scope 43 at $DIR/reference_prop.rs:+86:13: +86:14 +- _66 = &raw const _65; // scope 43 at $DIR/reference_prop.rs:+86:17: +86:29 +- StorageLive(_67); // scope 44 at $DIR/reference_prop.rs:+87:13: +87:14 +- _67 = &_66; // scope 44 at $DIR/reference_prop.rs:+87:17: +87:19 + StorageLive(_68); // scope 45 at $DIR/reference_prop.rs:+88:13: +88:14 +- _68 = (*_66); // scope 45 at $DIR/reference_prop.rs:+88:17: +88:19 ++ _68 = _65; // scope 45 at $DIR/reference_prop.rs:+88:17: +88:19 + StorageLive(_69); // scope 46 at $DIR/reference_prop.rs:+89:9: +89:19 + StorageLive(_70); // scope 46 at $DIR/reference_prop.rs:+89:16: +89:18 + _70 = (); // scope 46 at $DIR/reference_prop.rs:+89:16: +89:18 + _69 = opaque::<()>(move _70) -> bb10; // scope 46 at $DIR/reference_prop.rs:+89:9: +89:19 + // mir::Constant + // + span: $DIR/reference_prop.rs:285:9: 285:15 + // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + } + + bb10: { + StorageDead(_70); // scope 46 at $DIR/reference_prop.rs:+89:18: +89:19 + StorageDead(_69); // scope 46 at $DIR/reference_prop.rs:+89:19: +89:20 +- _64 = const (); // scope 42 at $DIR/reference_prop.rs:+84:5: +90:6 + StorageDead(_68); // scope 45 at $DIR/reference_prop.rs:+90:5: +90:6 +- StorageDead(_67); // scope 44 at $DIR/reference_prop.rs:+90:5: +90:6 +- StorageDead(_66); // scope 43 at $DIR/reference_prop.rs:+90:5: +90:6 + StorageDead(_65); // scope 42 at $DIR/reference_prop.rs:+90:5: +90:6 +- StorageDead(_64); // scope 0 at $DIR/reference_prop.rs:+90:5: +90:6 + StorageLive(_71); // scope 47 at $DIR/reference_prop.rs:+94:13: +94:14 + _71 = const 5_usize; // scope 47 at $DIR/reference_prop.rs:+94:17: +94:24 +- StorageLive(_72); // scope 48 at $DIR/reference_prop.rs:+95:13: +95:18 +- _72 = &raw const _71; // scope 48 at $DIR/reference_prop.rs:+95:21: +95:33 +- StorageLive(_73); // scope 49 at $DIR/reference_prop.rs:+96:13: +96:14 +- _73 = &mut _72; // scope 49 at $DIR/reference_prop.rs:+96:17: +96:23 + StorageLive(_74); // scope 50 at $DIR/reference_prop.rs:+97:13: +97:14 +- _74 = (*_72); // scope 50 at $DIR/reference_prop.rs:+97:17: +97:19 ++ _74 = _71; // scope 50 at $DIR/reference_prop.rs:+97:17: +97:19 + StorageLive(_75); // scope 51 at $DIR/reference_prop.rs:+98:9: +98:19 + StorageLive(_76); // scope 51 at $DIR/reference_prop.rs:+98:16: +98:18 + _76 = (); // scope 51 at $DIR/reference_prop.rs:+98:16: +98:18 + _75 = opaque::<()>(move _76) -> bb11; // scope 51 at $DIR/reference_prop.rs:+98:9: +98:19 + // mir::Constant + // + span: $DIR/reference_prop.rs:294:9: 294:15 + // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + } + + bb11: { + StorageDead(_76); // scope 51 at $DIR/reference_prop.rs:+98:18: +98:19 + StorageDead(_75); // scope 51 at $DIR/reference_prop.rs:+98:19: +98:20 + _0 = const (); // scope 47 at $DIR/reference_prop.rs:+93:5: +99:6 + StorageDead(_74); // scope 50 at $DIR/reference_prop.rs:+99:5: +99:6 +- StorageDead(_73); // scope 49 at $DIR/reference_prop.rs:+99:5: +99:6 +- StorageDead(_72); // scope 48 at $DIR/reference_prop.rs:+99:5: +99:6 + StorageDead(_71); // scope 47 at $DIR/reference_prop.rs:+99:5: +99:6 + return; // scope 0 at $DIR/reference_prop.rs:+100:2: +100:2 } } diff --git a/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff index 44ddbbc3066..8d059de5b87 100644 --- a/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.reference_propagation_mut.ReferencePropagation.diff @@ -17,12 +17,12 @@ let mut _17: (); // in scope 0 at $DIR/reference_prop.rs:+17:16: +17:18 let _18: (); // in scope 0 at $DIR/reference_prop.rs:+21:5: +27:6 let mut _19: usize; // in scope 0 at $DIR/reference_prop.rs:+22:13: +22:18 - let _23: (); // in scope 0 at $DIR/reference_prop.rs:+26:9: +26:19 - let mut _24: (); // in scope 0 at $DIR/reference_prop.rs:+26:16: +26:18 + let _23: (); // in scope 0 at $DIR/reference_prop.rs:+26:9: +26:18 + let mut _24: &&mut usize; // in scope 0 at $DIR/reference_prop.rs:+26:16: +26:17 let _25: (); // in scope 0 at $DIR/reference_prop.rs:+30:5: +36:6 let mut _26: usize; // in scope 0 at $DIR/reference_prop.rs:+31:13: +31:18 - let _30: (); // in scope 0 at $DIR/reference_prop.rs:+35:9: +35:19 - let mut _31: (); // in scope 0 at $DIR/reference_prop.rs:+35:16: +35:18 + let _30: (); // in scope 0 at $DIR/reference_prop.rs:+35:9: +35:18 + let mut _31: *mut &mut usize; // in scope 0 at $DIR/reference_prop.rs:+35:16: +35:17 let _32: (); // in scope 0 at $DIR/reference_prop.rs:+39:5: +44:6 let mut _33: usize; // in scope 0 at $DIR/reference_prop.rs:+40:13: +40:18 let _36: (); // in scope 0 at $DIR/reference_prop.rs:+43:9: +43:18 @@ -35,16 +35,25 @@ let _48: &mut T; // in scope 0 at $DIR/reference_prop.rs:+61:13: +61:14 let _50: (); // in scope 0 at $DIR/reference_prop.rs:+63:9: +63:19 let mut _51: (); // in scope 0 at $DIR/reference_prop.rs:+63:16: +63:18 - let _52: &mut T; // in scope 0 at $DIR/reference_prop.rs:+68:13: +68:14 - let mut _53: &mut T; // in scope 0 at $DIR/reference_prop.rs:+69:20: +69:32 + let _52: (); // in scope 0 at $DIR/reference_prop.rs:+67:5: +72:6 + let _53: &mut T; // in scope 0 at $DIR/reference_prop.rs:+68:13: +68:14 let mut _54: &mut T; // in scope 0 at $DIR/reference_prop.rs:+69:20: +69:32 - let _56: (); // in scope 0 at $DIR/reference_prop.rs:+71:9: +71:19 - let mut _57: (); // in scope 0 at $DIR/reference_prop.rs:+71:16: +71:18 + let mut _55: &mut T; // in scope 0 at $DIR/reference_prop.rs:+69:20: +69:32 + let _57: (); // in scope 0 at $DIR/reference_prop.rs:+71:9: +71:19 + let mut _58: (); // in scope 0 at $DIR/reference_prop.rs:+71:16: +71:18 + let _59: (); // in scope 0 at $DIR/reference_prop.rs:+75:5: +81:6 + let mut _60: usize; // in scope 0 at $DIR/reference_prop.rs:+76:13: +76:18 + let _64: (); // in scope 0 at $DIR/reference_prop.rs:+80:9: +80:19 + let mut _65: (); // in scope 0 at $DIR/reference_prop.rs:+80:16: +80:18 + let mut _66: usize; // in scope 0 at $DIR/reference_prop.rs:+85:13: +85:18 + let _70: (); // in scope 0 at $DIR/reference_prop.rs:+89:9: +89:19 + let mut _71: (); // in scope 0 at $DIR/reference_prop.rs:+89:16: +89:18 scope 1 { debug a => _4; // in scope 1 at $DIR/reference_prop.rs:+3:13: +3:18 let _5: &mut usize; // in scope 1 at $DIR/reference_prop.rs:+4:13: +4:14 scope 2 { - debug b => _5; // in scope 2 at $DIR/reference_prop.rs:+4:13: +4:14 +- debug b => _5; // in scope 2 at $DIR/reference_prop.rs:+4:13: +4:14 ++ debug b => &_4; // in scope 2 at $DIR/reference_prop.rs:+4:13: +4:14 let _6: usize; // in scope 2 at $DIR/reference_prop.rs:+5:13: +5:14 scope 3 { debug c => _6; // in scope 3 at $DIR/reference_prop.rs:+5:13: +5:14 @@ -86,7 +95,7 @@ let mut _27: &mut usize; // in scope 12 at $DIR/reference_prop.rs:+32:13: +32:18 scope 13 { debug b => _27; // in scope 13 at $DIR/reference_prop.rs:+32:13: +32:18 - let _28: &mut &mut usize; // in scope 13 at $DIR/reference_prop.rs:+33:13: +33:14 + let _28: *mut &mut usize; // in scope 13 at $DIR/reference_prop.rs:+33:13: +33:14 scope 14 { debug d => _28; // in scope 14 at $DIR/reference_prop.rs:+33:13: +33:14 let _29: usize; // in scope 14 at $DIR/reference_prop.rs:+34:13: +34:14 @@ -131,17 +140,52 @@ } } scope 25 { - debug a => _48; // in scope 25 at $DIR/reference_prop.rs:+61:13: +61:14 +- debug a => _48; // in scope 25 at $DIR/reference_prop.rs:+61:13: +61:14 ++ debug a => _1; // in scope 25 at $DIR/reference_prop.rs:+61:13: +61:14 let _49: T; // in scope 25 at $DIR/reference_prop.rs:+62:13: +62:14 scope 26 { debug b => _49; // in scope 26 at $DIR/reference_prop.rs:+62:13: +62:14 } } scope 27 { - debug a => _52; // in scope 27 at $DIR/reference_prop.rs:+68:13: +68:14 - let _55: T; // in scope 27 at $DIR/reference_prop.rs:+70:13: +70:14 + debug a => _53; // in scope 27 at $DIR/reference_prop.rs:+68:13: +68:14 + let _56: T; // in scope 27 at $DIR/reference_prop.rs:+70:13: +70:14 scope 28 { - debug b => _55; // in scope 28 at $DIR/reference_prop.rs:+70:13: +70:14 + debug b => _56; // in scope 28 at $DIR/reference_prop.rs:+70:13: +70:14 + } + } + scope 29 { + debug a => _60; // in scope 29 at $DIR/reference_prop.rs:+76:13: +76:18 + let _61: &mut usize; // in scope 29 at $DIR/reference_prop.rs:+77:13: +77:14 + scope 30 { +- debug b => _61; // in scope 30 at $DIR/reference_prop.rs:+77:13: +77:14 ++ debug b => &_60; // in scope 30 at $DIR/reference_prop.rs:+77:13: +77:14 + let _62: &&mut usize; // in scope 30 at $DIR/reference_prop.rs:+78:13: +78:14 + scope 31 { +- debug d => _62; // in scope 31 at $DIR/reference_prop.rs:+78:13: +78:14 ++ debug d => &&_60; // in scope 31 at $DIR/reference_prop.rs:+78:13: +78:14 + let _63: usize; // in scope 31 at $DIR/reference_prop.rs:+79:13: +79:14 + scope 32 { + debug c => _63; // in scope 32 at $DIR/reference_prop.rs:+79:13: +79:14 + } + } + } + } + scope 33 { + debug a => _66; // in scope 33 at $DIR/reference_prop.rs:+85:13: +85:18 + let mut _67: &mut usize; // in scope 33 at $DIR/reference_prop.rs:+86:13: +86:18 + scope 34 { +- debug b => _67; // in scope 34 at $DIR/reference_prop.rs:+86:13: +86:18 ++ debug b => &_66; // in scope 34 at $DIR/reference_prop.rs:+86:13: +86:18 + let _68: &mut &mut usize; // in scope 34 at $DIR/reference_prop.rs:+87:13: +87:14 + scope 35 { +- debug d => _68; // in scope 35 at $DIR/reference_prop.rs:+87:13: +87:14 ++ debug d => &&_66; // in scope 35 at $DIR/reference_prop.rs:+87:13: +87:14 + let _69: usize; // in scope 35 at $DIR/reference_prop.rs:+88:13: +88:14 + scope 36 { + debug c => _69; // in scope 36 at $DIR/reference_prop.rs:+88:13: +88:14 + } + } } } @@ -149,8 +193,8 @@ - StorageLive(_3); // scope 0 at $DIR/reference_prop.rs:+2:5: +7:6 StorageLive(_4); // scope 0 at $DIR/reference_prop.rs:+3:13: +3:18 _4 = const 5_usize; // scope 0 at $DIR/reference_prop.rs:+3:21: +3:28 - StorageLive(_5); // scope 1 at $DIR/reference_prop.rs:+4:13: +4:14 - _5 = &mut _4; // scope 1 at $DIR/reference_prop.rs:+4:17: +4:23 +- StorageLive(_5); // scope 1 at $DIR/reference_prop.rs:+4:13: +4:14 +- _5 = &mut _4; // scope 1 at $DIR/reference_prop.rs:+4:17: +4:23 StorageLive(_6); // scope 2 at $DIR/reference_prop.rs:+5:13: +5:14 - _6 = (*_5); // scope 2 at $DIR/reference_prop.rs:+5:17: +5:19 + _6 = _4; // scope 2 at $DIR/reference_prop.rs:+5:17: +5:19 @@ -159,7 +203,7 @@ _8 = (); // scope 3 at $DIR/reference_prop.rs:+6:16: +6:18 _7 = opaque::<()>(move _8) -> bb1; // scope 3 at $DIR/reference_prop.rs:+6:9: +6:19 // mir::Constant - // + span: $DIR/reference_prop.rs:91:9: 91:15 + // + span: $DIR/reference_prop.rs:109:9: 109:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } @@ -168,7 +212,7 @@ StorageDead(_7); // scope 3 at $DIR/reference_prop.rs:+6:19: +6:20 - _3 = const (); // scope 0 at $DIR/reference_prop.rs:+2:5: +7:6 StorageDead(_6); // scope 2 at $DIR/reference_prop.rs:+7:5: +7:6 - StorageDead(_5); // scope 1 at $DIR/reference_prop.rs:+7:5: +7:6 +- StorageDead(_5); // scope 1 at $DIR/reference_prop.rs:+7:5: +7:6 StorageDead(_4); // scope 0 at $DIR/reference_prop.rs:+7:5: +7:6 - StorageDead(_3); // scope 0 at $DIR/reference_prop.rs:+7:5: +7:6 - StorageLive(_9); // scope 0 at $DIR/reference_prop.rs:+10:5: +18:6 @@ -193,7 +237,7 @@ _17 = (); // scope 7 at $DIR/reference_prop.rs:+17:16: +17:18 _16 = opaque::<()>(move _17) -> bb2; // scope 7 at $DIR/reference_prop.rs:+17:9: +17:19 // mir::Constant - // + span: $DIR/reference_prop.rs:102:9: 102:15 + // + span: $DIR/reference_prop.rs:120:9: 120:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } @@ -215,18 +259,18 @@ _21 = &_20; // scope 9 at $DIR/reference_prop.rs:+24:17: +24:19 StorageLive(_22); // scope 10 at $DIR/reference_prop.rs:+25:13: +25:14 _22 = (*_20); // scope 10 at $DIR/reference_prop.rs:+25:17: +25:19 - StorageLive(_23); // scope 11 at $DIR/reference_prop.rs:+26:9: +26:19 - StorageLive(_24); // scope 11 at $DIR/reference_prop.rs:+26:16: +26:18 - _24 = (); // scope 11 at $DIR/reference_prop.rs:+26:16: +26:18 - _23 = opaque::<()>(move _24) -> bb3; // scope 11 at $DIR/reference_prop.rs:+26:9: +26:19 + StorageLive(_23); // scope 11 at $DIR/reference_prop.rs:+26:9: +26:18 + StorageLive(_24); // scope 11 at $DIR/reference_prop.rs:+26:16: +26:17 + _24 = _21; // scope 11 at $DIR/reference_prop.rs:+26:16: +26:17 + _23 = opaque::<&&mut usize>(move _24) -> bb3; // scope 11 at $DIR/reference_prop.rs:+26:9: +26:18 // mir::Constant - // + span: $DIR/reference_prop.rs:111:9: 111:15 - // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + // + span: $DIR/reference_prop.rs:129:9: 129:15 + // + literal: Const { ty: fn(&&mut usize) {opaque::<&&mut usize>}, val: Value(<ZST>) } } bb3: { - StorageDead(_24); // scope 11 at $DIR/reference_prop.rs:+26:18: +26:19 - StorageDead(_23); // scope 11 at $DIR/reference_prop.rs:+26:19: +26:20 + StorageDead(_24); // scope 11 at $DIR/reference_prop.rs:+26:17: +26:18 + StorageDead(_23); // scope 11 at $DIR/reference_prop.rs:+26:18: +26:19 - _18 = const (); // scope 0 at $DIR/reference_prop.rs:+21:5: +27:6 StorageDead(_22); // scope 10 at $DIR/reference_prop.rs:+27:5: +27:6 StorageDead(_21); // scope 9 at $DIR/reference_prop.rs:+27:5: +27:6 @@ -239,21 +283,21 @@ StorageLive(_27); // scope 12 at $DIR/reference_prop.rs:+32:13: +32:18 _27 = &mut _26; // scope 12 at $DIR/reference_prop.rs:+32:21: +32:27 StorageLive(_28); // scope 13 at $DIR/reference_prop.rs:+33:13: +33:14 - _28 = &mut _27; // scope 13 at $DIR/reference_prop.rs:+33:17: +33:23 + _28 = &raw mut _27; // scope 13 at $DIR/reference_prop.rs:+33:17: +33:27 StorageLive(_29); // scope 14 at $DIR/reference_prop.rs:+34:13: +34:14 _29 = (*_27); // scope 14 at $DIR/reference_prop.rs:+34:17: +34:19 - StorageLive(_30); // scope 15 at $DIR/reference_prop.rs:+35:9: +35:19 - StorageLive(_31); // scope 15 at $DIR/reference_prop.rs:+35:16: +35:18 - _31 = (); // scope 15 at $DIR/reference_prop.rs:+35:16: +35:18 - _30 = opaque::<()>(move _31) -> bb4; // scope 15 at $DIR/reference_prop.rs:+35:9: +35:19 + StorageLive(_30); // scope 15 at $DIR/reference_prop.rs:+35:9: +35:18 + StorageLive(_31); // scope 15 at $DIR/reference_prop.rs:+35:16: +35:17 + _31 = _28; // scope 15 at $DIR/reference_prop.rs:+35:16: +35:17 + _30 = opaque::<*mut &mut usize>(move _31) -> bb4; // scope 15 at $DIR/reference_prop.rs:+35:9: +35:18 // mir::Constant - // + span: $DIR/reference_prop.rs:120:9: 120:15 - // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + // + span: $DIR/reference_prop.rs:138:9: 138:15 + // + literal: Const { ty: fn(*mut &mut usize) {opaque::<*mut &mut usize>}, val: Value(<ZST>) } } bb4: { - StorageDead(_31); // scope 15 at $DIR/reference_prop.rs:+35:18: +35:19 - StorageDead(_30); // scope 15 at $DIR/reference_prop.rs:+35:19: +35:20 + StorageDead(_31); // scope 15 at $DIR/reference_prop.rs:+35:17: +35:18 + StorageDead(_30); // scope 15 at $DIR/reference_prop.rs:+35:18: +35:19 - _25 = const (); // scope 0 at $DIR/reference_prop.rs:+30:5: +36:6 StorageDead(_29); // scope 14 at $DIR/reference_prop.rs:+36:5: +36:6 StorageDead(_28); // scope 13 at $DIR/reference_prop.rs:+36:5: +36:6 @@ -272,7 +316,7 @@ _37 = move _34; // scope 18 at $DIR/reference_prop.rs:+43:16: +43:17 _36 = opaque::<&mut usize>(move _37) -> bb5; // scope 18 at $DIR/reference_prop.rs:+43:9: +43:18 // mir::Constant - // + span: $DIR/reference_prop.rs:128:9: 128:15 + // + span: $DIR/reference_prop.rs:146:9: 146:15 // + literal: Const { ty: fn(&mut usize) {opaque::<&mut usize>}, val: Value(<ZST>) } } @@ -302,7 +346,7 @@ _46 = move _44; // scope 24 at $DIR/reference_prop.rs:+56:16: +56:18 _45 = opaque::<&mut usize>(move _46) -> bb6; // scope 24 at $DIR/reference_prop.rs:+56:9: +56:19 // mir::Constant - // + span: $DIR/reference_prop.rs:141:9: 141:15 + // + span: $DIR/reference_prop.rs:159:9: 159:15 // + literal: Const { ty: fn(&mut usize) {opaque::<&mut usize>}, val: Value(<ZST>) } } @@ -318,8 +362,8 @@ StorageDead(_39); // scope 0 at $DIR/reference_prop.rs:+57:5: +57:6 - StorageDead(_38); // scope 0 at $DIR/reference_prop.rs:+57:5: +57:6 - StorageLive(_47); // scope 0 at $DIR/reference_prop.rs:+60:5: +64:6 - StorageLive(_48); // scope 0 at $DIR/reference_prop.rs:+61:13: +61:14 - _48 = &mut (*_1); // scope 0 at $DIR/reference_prop.rs:+61:17: +61:29 +- StorageLive(_48); // scope 0 at $DIR/reference_prop.rs:+61:13: +61:14 +- _48 = &mut (*_1); // scope 0 at $DIR/reference_prop.rs:+61:17: +61:29 StorageLive(_49); // scope 25 at $DIR/reference_prop.rs:+62:13: +62:14 - _49 = (*_48); // scope 25 at $DIR/reference_prop.rs:+62:17: +62:19 + _49 = (*_1); // scope 25 at $DIR/reference_prop.rs:+62:17: +62:19 @@ -328,7 +372,7 @@ _51 = (); // scope 26 at $DIR/reference_prop.rs:+63:16: +63:18 _50 = opaque::<()>(move _51) -> bb7; // scope 26 at $DIR/reference_prop.rs:+63:9: +63:19 // mir::Constant - // + span: $DIR/reference_prop.rs:148:9: 148:15 + // + span: $DIR/reference_prop.rs:166:9: 166:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } @@ -337,36 +381,92 @@ StorageDead(_50); // scope 26 at $DIR/reference_prop.rs:+63:19: +63:20 - _47 = const (); // scope 0 at $DIR/reference_prop.rs:+60:5: +64:6 StorageDead(_49); // scope 25 at $DIR/reference_prop.rs:+64:5: +64:6 - StorageDead(_48); // scope 0 at $DIR/reference_prop.rs:+64:5: +64:6 +- StorageDead(_48); // scope 0 at $DIR/reference_prop.rs:+64:5: +64:6 - StorageDead(_47); // scope 0 at $DIR/reference_prop.rs:+64:5: +64:6 - StorageLive(_52); // scope 0 at $DIR/reference_prop.rs:+68:13: +68:14 - _52 = &mut (*_2); // scope 0 at $DIR/reference_prop.rs:+68:17: +68:31 - StorageLive(_53); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:32 -- StorageLive(_54); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:32 -- _54 = &mut (*_1); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:32 -- _53 = &mut (*_54); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:32 -+ _53 = &mut (*_1); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:32 - _2 = move _53; // scope 27 at $DIR/reference_prop.rs:+69:9: +69:32 - StorageDead(_53); // scope 27 at $DIR/reference_prop.rs:+69:31: +69:32 -- StorageDead(_54); // scope 27 at $DIR/reference_prop.rs:+69:32: +69:33 - StorageLive(_55); // scope 27 at $DIR/reference_prop.rs:+70:13: +70:14 - _55 = (*_52); // scope 27 at $DIR/reference_prop.rs:+70:17: +70:19 - StorageLive(_56); // scope 28 at $DIR/reference_prop.rs:+71:9: +71:19 - StorageLive(_57); // scope 28 at $DIR/reference_prop.rs:+71:16: +71:18 - _57 = (); // scope 28 at $DIR/reference_prop.rs:+71:16: +71:18 - _56 = opaque::<()>(move _57) -> bb8; // scope 28 at $DIR/reference_prop.rs:+71:9: +71:19 +- StorageLive(_52); // scope 0 at $DIR/reference_prop.rs:+67:5: +72:6 + StorageLive(_53); // scope 0 at $DIR/reference_prop.rs:+68:13: +68:14 + _53 = &mut (*_2); // scope 0 at $DIR/reference_prop.rs:+68:17: +68:31 + StorageLive(_54); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:32 +- StorageLive(_55); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:32 +- _55 = &mut (*_1); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:32 +- _54 = &mut (*_55); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:32 ++ _54 = &mut (*_1); // scope 27 at $DIR/reference_prop.rs:+69:20: +69:32 + _2 = move _54; // scope 27 at $DIR/reference_prop.rs:+69:9: +69:32 + StorageDead(_54); // scope 27 at $DIR/reference_prop.rs:+69:31: +69:32 +- StorageDead(_55); // scope 27 at $DIR/reference_prop.rs:+69:32: +69:33 + StorageLive(_56); // scope 27 at $DIR/reference_prop.rs:+70:13: +70:14 + _56 = (*_53); // scope 27 at $DIR/reference_prop.rs:+70:17: +70:19 + StorageLive(_57); // scope 28 at $DIR/reference_prop.rs:+71:9: +71:19 + StorageLive(_58); // scope 28 at $DIR/reference_prop.rs:+71:16: +71:18 + _58 = (); // scope 28 at $DIR/reference_prop.rs:+71:16: +71:18 + _57 = opaque::<()>(move _58) -> bb8; // scope 28 at $DIR/reference_prop.rs:+71:9: +71:19 // mir::Constant - // + span: $DIR/reference_prop.rs:156:9: 156:15 + // + span: $DIR/reference_prop.rs:174:9: 174:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } bb8: { - StorageDead(_57); // scope 28 at $DIR/reference_prop.rs:+71:18: +71:19 - StorageDead(_56); // scope 28 at $DIR/reference_prop.rs:+71:19: +71:20 - _0 = const (); // scope 0 at $DIR/reference_prop.rs:+67:5: +72:6 - StorageDead(_55); // scope 27 at $DIR/reference_prop.rs:+72:5: +72:6 - StorageDead(_52); // scope 0 at $DIR/reference_prop.rs:+72:5: +72:6 - return; // scope 0 at $DIR/reference_prop.rs:+73:2: +73:2 + StorageDead(_58); // scope 28 at $DIR/reference_prop.rs:+71:18: +71:19 + StorageDead(_57); // scope 28 at $DIR/reference_prop.rs:+71:19: +71:20 +- _52 = const (); // scope 0 at $DIR/reference_prop.rs:+67:5: +72:6 + StorageDead(_56); // scope 27 at $DIR/reference_prop.rs:+72:5: +72:6 + StorageDead(_53); // scope 0 at $DIR/reference_prop.rs:+72:5: +72:6 +- StorageDead(_52); // scope 0 at $DIR/reference_prop.rs:+72:5: +72:6 +- StorageLive(_59); // scope 0 at $DIR/reference_prop.rs:+75:5: +81:6 + StorageLive(_60); // scope 0 at $DIR/reference_prop.rs:+76:13: +76:18 + _60 = const 5_usize; // scope 0 at $DIR/reference_prop.rs:+76:21: +76:28 +- StorageLive(_61); // scope 29 at $DIR/reference_prop.rs:+77:13: +77:14 +- _61 = &mut _60; // scope 29 at $DIR/reference_prop.rs:+77:17: +77:23 +- StorageLive(_62); // scope 30 at $DIR/reference_prop.rs:+78:13: +78:14 +- _62 = &_61; // scope 30 at $DIR/reference_prop.rs:+78:17: +78:19 + StorageLive(_63); // scope 31 at $DIR/reference_prop.rs:+79:13: +79:14 +- _63 = (*_61); // scope 31 at $DIR/reference_prop.rs:+79:17: +79:19 ++ _63 = _60; // scope 31 at $DIR/reference_prop.rs:+79:17: +79:19 + StorageLive(_64); // scope 32 at $DIR/reference_prop.rs:+80:9: +80:19 + StorageLive(_65); // scope 32 at $DIR/reference_prop.rs:+80:16: +80:18 + _65 = (); // scope 32 at $DIR/reference_prop.rs:+80:16: +80:18 + _64 = opaque::<()>(move _65) -> bb9; // scope 32 at $DIR/reference_prop.rs:+80:9: +80:19 + // mir::Constant + // + span: $DIR/reference_prop.rs:183:9: 183:15 + // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + } + + bb9: { + StorageDead(_65); // scope 32 at $DIR/reference_prop.rs:+80:18: +80:19 + StorageDead(_64); // scope 32 at $DIR/reference_prop.rs:+80:19: +80:20 +- _59 = const (); // scope 0 at $DIR/reference_prop.rs:+75:5: +81:6 + StorageDead(_63); // scope 31 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageDead(_62); // scope 30 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageDead(_61); // scope 29 at $DIR/reference_prop.rs:+81:5: +81:6 + StorageDead(_60); // scope 0 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageDead(_59); // scope 0 at $DIR/reference_prop.rs:+81:5: +81:6 + StorageLive(_66); // scope 0 at $DIR/reference_prop.rs:+85:13: +85:18 + _66 = const 5_usize; // scope 0 at $DIR/reference_prop.rs:+85:21: +85:28 +- StorageLive(_67); // scope 33 at $DIR/reference_prop.rs:+86:13: +86:18 +- _67 = &mut _66; // scope 33 at $DIR/reference_prop.rs:+86:21: +86:27 +- StorageLive(_68); // scope 34 at $DIR/reference_prop.rs:+87:13: +87:14 +- _68 = &mut _67; // scope 34 at $DIR/reference_prop.rs:+87:17: +87:23 + StorageLive(_69); // scope 35 at $DIR/reference_prop.rs:+88:13: +88:14 +- _69 = (*_67); // scope 35 at $DIR/reference_prop.rs:+88:17: +88:19 ++ _69 = _66; // scope 35 at $DIR/reference_prop.rs:+88:17: +88:19 + StorageLive(_70); // scope 36 at $DIR/reference_prop.rs:+89:9: +89:19 + StorageLive(_71); // scope 36 at $DIR/reference_prop.rs:+89:16: +89:18 + _71 = (); // scope 36 at $DIR/reference_prop.rs:+89:16: +89:18 + _70 = opaque::<()>(move _71) -> bb10; // scope 36 at $DIR/reference_prop.rs:+89:9: +89:19 + // mir::Constant + // + span: $DIR/reference_prop.rs:192:9: 192:15 + // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + } + + bb10: { + StorageDead(_71); // scope 36 at $DIR/reference_prop.rs:+89:18: +89:19 + StorageDead(_70); // scope 36 at $DIR/reference_prop.rs:+89:19: +89:20 + _0 = const (); // scope 0 at $DIR/reference_prop.rs:+84:5: +90:6 + StorageDead(_69); // scope 35 at $DIR/reference_prop.rs:+90:5: +90:6 +- StorageDead(_68); // scope 34 at $DIR/reference_prop.rs:+90:5: +90:6 +- StorageDead(_67); // scope 33 at $DIR/reference_prop.rs:+90:5: +90:6 + StorageDead(_66); // scope 0 at $DIR/reference_prop.rs:+90:5: +90:6 + return; // scope 0 at $DIR/reference_prop.rs:+91:2: +91:2 } } diff --git a/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff b/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff index c55b5eb4bed..c93aa52be11 100644 --- a/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.reference_propagation_mut_ptr.ReferencePropagation.diff @@ -13,11 +13,11 @@ let _15: (); // in scope 0 at $DIR/reference_prop.rs:+17:9: +17:19 let mut _16: (); // in scope 0 at $DIR/reference_prop.rs:+17:16: +17:18 let _17: (); // in scope 0 at $DIR/reference_prop.rs:+21:5: +27:6 - let _22: (); // in scope 0 at $DIR/reference_prop.rs:+26:9: +26:19 - let mut _23: (); // in scope 0 at $DIR/reference_prop.rs:+26:16: +26:18 + let _22: (); // in scope 0 at $DIR/reference_prop.rs:+26:9: +26:18 + let mut _23: &*mut usize; // in scope 0 at $DIR/reference_prop.rs:+26:16: +26:17 let _24: (); // in scope 0 at $DIR/reference_prop.rs:+30:5: +36:6 - let _29: (); // in scope 0 at $DIR/reference_prop.rs:+35:9: +35:19 - let mut _30: (); // in scope 0 at $DIR/reference_prop.rs:+35:16: +35:18 + let _29: (); // in scope 0 at $DIR/reference_prop.rs:+35:9: +35:18 + let mut _30: *mut *mut usize; // in scope 0 at $DIR/reference_prop.rs:+35:16: +35:17 let _31: (); // in scope 0 at $DIR/reference_prop.rs:+39:5: +44:6 let _35: (); // in scope 0 at $DIR/reference_prop.rs:+43:9: +43:18 let mut _36: *mut usize; // in scope 0 at $DIR/reference_prop.rs:+43:16: +43:17 @@ -27,16 +27,23 @@ let _46: (); // in scope 0 at $DIR/reference_prop.rs:+60:5: +64:6 let _49: (); // in scope 0 at $DIR/reference_prop.rs:+63:9: +63:19 let mut _50: (); // in scope 0 at $DIR/reference_prop.rs:+63:16: +63:18 - let mut _52: *mut T; // in scope 0 at $DIR/reference_prop.rs:+69:20: +69:36 - let _54: (); // in scope 0 at $DIR/reference_prop.rs:+71:9: +71:19 - let mut _55: (); // in scope 0 at $DIR/reference_prop.rs:+71:16: +71:18 + let _51: (); // in scope 0 at $DIR/reference_prop.rs:+67:5: +72:6 + let mut _53: *mut T; // in scope 0 at $DIR/reference_prop.rs:+69:20: +69:36 + let _55: (); // in scope 0 at $DIR/reference_prop.rs:+71:9: +71:19 + let mut _56: (); // in scope 0 at $DIR/reference_prop.rs:+71:16: +71:18 + let _57: (); // in scope 0 at $DIR/reference_prop.rs:+75:5: +81:6 + let _62: (); // in scope 0 at $DIR/reference_prop.rs:+80:9: +80:19 + let mut _63: (); // in scope 0 at $DIR/reference_prop.rs:+80:16: +80:18 + let _68: (); // in scope 0 at $DIR/reference_prop.rs:+89:9: +89:19 + let mut _69: (); // in scope 0 at $DIR/reference_prop.rs:+89:16: +89:18 scope 1 { let mut _4: usize; // in scope 1 at $DIR/reference_prop.rs:+3:13: +3:18 scope 2 { debug a => _4; // in scope 2 at $DIR/reference_prop.rs:+3:13: +3:18 let _5: *mut usize; // in scope 2 at $DIR/reference_prop.rs:+4:13: +4:14 scope 3 { - debug b => _5; // in scope 3 at $DIR/reference_prop.rs:+4:13: +4:14 +- debug b => _5; // in scope 3 at $DIR/reference_prop.rs:+4:13: +4:14 ++ debug b => &_4; // in scope 3 at $DIR/reference_prop.rs:+4:13: +4:14 let _6: usize; // in scope 3 at $DIR/reference_prop.rs:+5:13: +5:14 scope 4 { debug c => _6; // in scope 4 at $DIR/reference_prop.rs:+5:13: +5:14 @@ -87,7 +94,7 @@ let mut _26: *mut usize; // in scope 16 at $DIR/reference_prop.rs:+32:13: +32:18 scope 17 { debug b => _26; // in scope 17 at $DIR/reference_prop.rs:+32:13: +32:18 - let _27: &mut *mut usize; // in scope 17 at $DIR/reference_prop.rs:+33:13: +33:14 + let _27: *mut *mut usize; // in scope 17 at $DIR/reference_prop.rs:+33:13: +33:14 scope 18 { debug d => _27; // in scope 18 at $DIR/reference_prop.rs:+33:13: +33:14 let _28: usize; // in scope 18 at $DIR/reference_prop.rs:+34:13: +34:14 @@ -141,7 +148,8 @@ scope 31 { let _47: *mut T; // in scope 31 at $DIR/reference_prop.rs:+61:13: +61:14 scope 32 { - debug a => _47; // in scope 32 at $DIR/reference_prop.rs:+61:13: +61:14 +- debug a => _47; // in scope 32 at $DIR/reference_prop.rs:+61:13: +61:14 ++ debug a => _1; // in scope 32 at $DIR/reference_prop.rs:+61:13: +61:14 let _48: T; // in scope 32 at $DIR/reference_prop.rs:+62:13: +62:14 scope 33 { debug b => _48; // in scope 33 at $DIR/reference_prop.rs:+62:13: +62:14 @@ -149,12 +157,52 @@ } } scope 34 { - let _51: *mut T; // in scope 34 at $DIR/reference_prop.rs:+68:13: +68:14 + let _52: *mut T; // in scope 34 at $DIR/reference_prop.rs:+68:13: +68:14 scope 35 { - debug a => _51; // in scope 35 at $DIR/reference_prop.rs:+68:13: +68:14 - let _53: T; // in scope 35 at $DIR/reference_prop.rs:+70:13: +70:14 + debug a => _52; // in scope 35 at $DIR/reference_prop.rs:+68:13: +68:14 + let _54: T; // in scope 35 at $DIR/reference_prop.rs:+70:13: +70:14 scope 36 { - debug b => _53; // in scope 36 at $DIR/reference_prop.rs:+70:13: +70:14 + debug b => _54; // in scope 36 at $DIR/reference_prop.rs:+70:13: +70:14 + } + } + } + scope 37 { + let mut _58: usize; // in scope 37 at $DIR/reference_prop.rs:+76:13: +76:18 + scope 38 { + debug a => _58; // in scope 38 at $DIR/reference_prop.rs:+76:13: +76:18 + let _59: *mut usize; // in scope 38 at $DIR/reference_prop.rs:+77:13: +77:14 + scope 39 { +- debug b => _59; // in scope 39 at $DIR/reference_prop.rs:+77:13: +77:14 ++ debug b => &_58; // in scope 39 at $DIR/reference_prop.rs:+77:13: +77:14 + let _60: &*mut usize; // in scope 39 at $DIR/reference_prop.rs:+78:13: +78:14 + scope 40 { +- debug d => _60; // in scope 40 at $DIR/reference_prop.rs:+78:13: +78:14 ++ debug d => &&_58; // in scope 40 at $DIR/reference_prop.rs:+78:13: +78:14 + let _61: usize; // in scope 40 at $DIR/reference_prop.rs:+79:13: +79:14 + scope 41 { + debug c => _61; // in scope 41 at $DIR/reference_prop.rs:+79:13: +79:14 + } + } + } + } + } + scope 42 { + let mut _64: usize; // in scope 42 at $DIR/reference_prop.rs:+85:13: +85:18 + scope 43 { + debug a => _64; // in scope 43 at $DIR/reference_prop.rs:+85:13: +85:18 + let mut _65: *mut usize; // in scope 43 at $DIR/reference_prop.rs:+86:13: +86:18 + scope 44 { +- debug b => _65; // in scope 44 at $DIR/reference_prop.rs:+86:13: +86:18 ++ debug b => &_64; // in scope 44 at $DIR/reference_prop.rs:+86:13: +86:18 + let _66: &mut *mut usize; // in scope 44 at $DIR/reference_prop.rs:+87:13: +87:14 + scope 45 { +- debug d => _66; // in scope 45 at $DIR/reference_prop.rs:+87:13: +87:14 ++ debug d => &&_64; // in scope 45 at $DIR/reference_prop.rs:+87:13: +87:14 + let _67: usize; // in scope 45 at $DIR/reference_prop.rs:+88:13: +88:14 + scope 46 { + debug c => _67; // in scope 46 at $DIR/reference_prop.rs:+88:13: +88:14 + } + } } } } @@ -163,8 +211,8 @@ - StorageLive(_3); // scope 0 at $DIR/reference_prop.rs:+2:5: +7:6 StorageLive(_4); // scope 1 at $DIR/reference_prop.rs:+3:13: +3:18 _4 = const 5_usize; // scope 1 at $DIR/reference_prop.rs:+3:21: +3:28 - StorageLive(_5); // scope 2 at $DIR/reference_prop.rs:+4:13: +4:14 - _5 = &raw mut _4; // scope 2 at $DIR/reference_prop.rs:+4:17: +4:27 +- StorageLive(_5); // scope 2 at $DIR/reference_prop.rs:+4:13: +4:14 +- _5 = &raw mut _4; // scope 2 at $DIR/reference_prop.rs:+4:17: +4:27 StorageLive(_6); // scope 3 at $DIR/reference_prop.rs:+5:13: +5:14 - _6 = (*_5); // scope 3 at $DIR/reference_prop.rs:+5:17: +5:19 + _6 = _4; // scope 3 at $DIR/reference_prop.rs:+5:17: +5:19 @@ -173,7 +221,7 @@ _8 = (); // scope 4 at $DIR/reference_prop.rs:+6:16: +6:18 _7 = opaque::<()>(move _8) -> bb1; // scope 4 at $DIR/reference_prop.rs:+6:9: +6:19 // mir::Constant - // + span: $DIR/reference_prop.rs:250:9: 250:15 + // + span: $DIR/reference_prop.rs:304:9: 304:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } @@ -182,7 +230,7 @@ StorageDead(_7); // scope 4 at $DIR/reference_prop.rs:+6:19: +6:20 - _3 = const (); // scope 1 at $DIR/reference_prop.rs:+2:5: +7:6 StorageDead(_6); // scope 3 at $DIR/reference_prop.rs:+7:5: +7:6 - StorageDead(_5); // scope 2 at $DIR/reference_prop.rs:+7:5: +7:6 +- StorageDead(_5); // scope 2 at $DIR/reference_prop.rs:+7:5: +7:6 StorageDead(_4); // scope 1 at $DIR/reference_prop.rs:+7:5: +7:6 - StorageDead(_3); // scope 0 at $DIR/reference_prop.rs:+7:5: +7:6 - StorageLive(_9); // scope 0 at $DIR/reference_prop.rs:+10:5: +18:6 @@ -203,7 +251,7 @@ _16 = (); // scope 9 at $DIR/reference_prop.rs:+17:16: +17:18 _15 = opaque::<()>(move _16) -> bb2; // scope 9 at $DIR/reference_prop.rs:+17:9: +17:19 // mir::Constant - // + span: $DIR/reference_prop.rs:261:9: 261:15 + // + span: $DIR/reference_prop.rs:315:9: 315:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } @@ -225,18 +273,18 @@ _20 = &_19; // scope 12 at $DIR/reference_prop.rs:+24:17: +24:19 StorageLive(_21); // scope 13 at $DIR/reference_prop.rs:+25:13: +25:14 _21 = (*_19); // scope 13 at $DIR/reference_prop.rs:+25:17: +25:19 - StorageLive(_22); // scope 14 at $DIR/reference_prop.rs:+26:9: +26:19 - StorageLive(_23); // scope 14 at $DIR/reference_prop.rs:+26:16: +26:18 - _23 = (); // scope 14 at $DIR/reference_prop.rs:+26:16: +26:18 - _22 = opaque::<()>(move _23) -> bb3; // scope 14 at $DIR/reference_prop.rs:+26:9: +26:19 + StorageLive(_22); // scope 14 at $DIR/reference_prop.rs:+26:9: +26:18 + StorageLive(_23); // scope 14 at $DIR/reference_prop.rs:+26:16: +26:17 + _23 = _20; // scope 14 at $DIR/reference_prop.rs:+26:16: +26:17 + _22 = opaque::<&*mut usize>(move _23) -> bb3; // scope 14 at $DIR/reference_prop.rs:+26:9: +26:18 // mir::Constant - // + span: $DIR/reference_prop.rs:270:9: 270:15 - // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + // + span: $DIR/reference_prop.rs:324:9: 324:15 + // + literal: Const { ty: fn(&*mut usize) {opaque::<&*mut usize>}, val: Value(<ZST>) } } bb3: { - StorageDead(_23); // scope 14 at $DIR/reference_prop.rs:+26:18: +26:19 - StorageDead(_22); // scope 14 at $DIR/reference_prop.rs:+26:19: +26:20 + StorageDead(_23); // scope 14 at $DIR/reference_prop.rs:+26:17: +26:18 + StorageDead(_22); // scope 14 at $DIR/reference_prop.rs:+26:18: +26:19 - _17 = const (); // scope 10 at $DIR/reference_prop.rs:+21:5: +27:6 StorageDead(_21); // scope 13 at $DIR/reference_prop.rs:+27:5: +27:6 StorageDead(_20); // scope 12 at $DIR/reference_prop.rs:+27:5: +27:6 @@ -249,21 +297,21 @@ StorageLive(_26); // scope 16 at $DIR/reference_prop.rs:+32:13: +32:18 _26 = &raw mut _25; // scope 16 at $DIR/reference_prop.rs:+32:21: +32:31 StorageLive(_27); // scope 17 at $DIR/reference_prop.rs:+33:13: +33:14 - _27 = &mut _26; // scope 17 at $DIR/reference_prop.rs:+33:17: +33:23 + _27 = &raw mut _26; // scope 17 at $DIR/reference_prop.rs:+33:17: +33:27 StorageLive(_28); // scope 18 at $DIR/reference_prop.rs:+34:13: +34:14 _28 = (*_26); // scope 18 at $DIR/reference_prop.rs:+34:17: +34:19 - StorageLive(_29); // scope 19 at $DIR/reference_prop.rs:+35:9: +35:19 - StorageLive(_30); // scope 19 at $DIR/reference_prop.rs:+35:16: +35:18 - _30 = (); // scope 19 at $DIR/reference_prop.rs:+35:16: +35:18 - _29 = opaque::<()>(move _30) -> bb4; // scope 19 at $DIR/reference_prop.rs:+35:9: +35:19 + StorageLive(_29); // scope 19 at $DIR/reference_prop.rs:+35:9: +35:18 + StorageLive(_30); // scope 19 at $DIR/reference_prop.rs:+35:16: +35:17 + _30 = _27; // scope 19 at $DIR/reference_prop.rs:+35:16: +35:17 + _29 = opaque::<*mut *mut usize>(move _30) -> bb4; // scope 19 at $DIR/reference_prop.rs:+35:9: +35:18 // mir::Constant - // + span: $DIR/reference_prop.rs:279:9: 279:15 - // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + // + span: $DIR/reference_prop.rs:333:9: 333:15 + // + literal: Const { ty: fn(*mut *mut usize) {opaque::<*mut *mut usize>}, val: Value(<ZST>) } } bb4: { - StorageDead(_30); // scope 19 at $DIR/reference_prop.rs:+35:18: +35:19 - StorageDead(_29); // scope 19 at $DIR/reference_prop.rs:+35:19: +35:20 + StorageDead(_30); // scope 19 at $DIR/reference_prop.rs:+35:17: +35:18 + StorageDead(_29); // scope 19 at $DIR/reference_prop.rs:+35:18: +35:19 - _24 = const (); // scope 15 at $DIR/reference_prop.rs:+30:5: +36:6 StorageDead(_28); // scope 18 at $DIR/reference_prop.rs:+36:5: +36:6 StorageDead(_27); // scope 17 at $DIR/reference_prop.rs:+36:5: +36:6 @@ -282,7 +330,7 @@ _36 = _33; // scope 23 at $DIR/reference_prop.rs:+43:16: +43:17 _35 = opaque::<*mut usize>(move _36) -> bb5; // scope 23 at $DIR/reference_prop.rs:+43:9: +43:18 // mir::Constant - // + span: $DIR/reference_prop.rs:287:9: 287:15 + // + span: $DIR/reference_prop.rs:341:9: 341:15 // + literal: Const { ty: fn(*mut usize) {opaque::<*mut usize>}, val: Value(<ZST>) } } @@ -312,7 +360,7 @@ _45 = _43; // scope 30 at $DIR/reference_prop.rs:+56:16: +56:18 _44 = opaque::<*mut usize>(move _45) -> bb6; // scope 30 at $DIR/reference_prop.rs:+56:9: +56:19 // mir::Constant - // + span: $DIR/reference_prop.rs:300:9: 300:15 + // + span: $DIR/reference_prop.rs:354:9: 354:15 // + literal: Const { ty: fn(*mut usize) {opaque::<*mut usize>}, val: Value(<ZST>) } } @@ -328,8 +376,8 @@ StorageDead(_38); // scope 24 at $DIR/reference_prop.rs:+57:5: +57:6 - StorageDead(_37); // scope 0 at $DIR/reference_prop.rs:+57:5: +57:6 - StorageLive(_46); // scope 0 at $DIR/reference_prop.rs:+60:5: +64:6 - StorageLive(_47); // scope 31 at $DIR/reference_prop.rs:+61:13: +61:14 - _47 = &raw mut (*_1); // scope 31 at $DIR/reference_prop.rs:+61:17: +61:33 +- StorageLive(_47); // scope 31 at $DIR/reference_prop.rs:+61:13: +61:14 +- _47 = &raw mut (*_1); // scope 31 at $DIR/reference_prop.rs:+61:17: +61:33 StorageLive(_48); // scope 32 at $DIR/reference_prop.rs:+62:13: +62:14 - _48 = (*_47); // scope 32 at $DIR/reference_prop.rs:+62:17: +62:19 + _48 = (*_1); // scope 32 at $DIR/reference_prop.rs:+62:17: +62:19 @@ -338,7 +386,7 @@ _50 = (); // scope 33 at $DIR/reference_prop.rs:+63:16: +63:18 _49 = opaque::<()>(move _50) -> bb7; // scope 33 at $DIR/reference_prop.rs:+63:9: +63:19 // mir::Constant - // + span: $DIR/reference_prop.rs:307:9: 307:15 + // + span: $DIR/reference_prop.rs:361:9: 361:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } @@ -347,32 +395,88 @@ StorageDead(_49); // scope 33 at $DIR/reference_prop.rs:+63:19: +63:20 - _46 = const (); // scope 31 at $DIR/reference_prop.rs:+60:5: +64:6 StorageDead(_48); // scope 32 at $DIR/reference_prop.rs:+64:5: +64:6 - StorageDead(_47); // scope 31 at $DIR/reference_prop.rs:+64:5: +64:6 +- StorageDead(_47); // scope 31 at $DIR/reference_prop.rs:+64:5: +64:6 - StorageDead(_46); // scope 0 at $DIR/reference_prop.rs:+64:5: +64:6 - StorageLive(_51); // scope 34 at $DIR/reference_prop.rs:+68:13: +68:14 - _51 = &raw mut (*_2); // scope 34 at $DIR/reference_prop.rs:+68:17: +68:35 - StorageLive(_52); // scope 35 at $DIR/reference_prop.rs:+69:20: +69:36 - _52 = &raw mut (*_1); // scope 35 at $DIR/reference_prop.rs:+69:20: +69:36 - _2 = move _52; // scope 35 at $DIR/reference_prop.rs:+69:9: +69:36 - StorageDead(_52); // scope 35 at $DIR/reference_prop.rs:+69:35: +69:36 - StorageLive(_53); // scope 35 at $DIR/reference_prop.rs:+70:13: +70:14 - _53 = (*_51); // scope 35 at $DIR/reference_prop.rs:+70:17: +70:19 - StorageLive(_54); // scope 36 at $DIR/reference_prop.rs:+71:9: +71:19 - StorageLive(_55); // scope 36 at $DIR/reference_prop.rs:+71:16: +71:18 - _55 = (); // scope 36 at $DIR/reference_prop.rs:+71:16: +71:18 - _54 = opaque::<()>(move _55) -> bb8; // scope 36 at $DIR/reference_prop.rs:+71:9: +71:19 +- StorageLive(_51); // scope 0 at $DIR/reference_prop.rs:+67:5: +72:6 + StorageLive(_52); // scope 34 at $DIR/reference_prop.rs:+68:13: +68:14 + _52 = &raw mut (*_2); // scope 34 at $DIR/reference_prop.rs:+68:17: +68:35 + StorageLive(_53); // scope 35 at $DIR/reference_prop.rs:+69:20: +69:36 + _53 = &raw mut (*_1); // scope 35 at $DIR/reference_prop.rs:+69:20: +69:36 + _2 = move _53; // scope 35 at $DIR/reference_prop.rs:+69:9: +69:36 + StorageDead(_53); // scope 35 at $DIR/reference_prop.rs:+69:35: +69:36 + StorageLive(_54); // scope 35 at $DIR/reference_prop.rs:+70:13: +70:14 + _54 = (*_52); // scope 35 at $DIR/reference_prop.rs:+70:17: +70:19 + StorageLive(_55); // scope 36 at $DIR/reference_prop.rs:+71:9: +71:19 + StorageLive(_56); // scope 36 at $DIR/reference_prop.rs:+71:16: +71:18 + _56 = (); // scope 36 at $DIR/reference_prop.rs:+71:16: +71:18 + _55 = opaque::<()>(move _56) -> bb8; // scope 36 at $DIR/reference_prop.rs:+71:9: +71:19 // mir::Constant - // + span: $DIR/reference_prop.rs:315:9: 315:15 + // + span: $DIR/reference_prop.rs:369:9: 369:15 // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } } bb8: { - StorageDead(_55); // scope 36 at $DIR/reference_prop.rs:+71:18: +71:19 - StorageDead(_54); // scope 36 at $DIR/reference_prop.rs:+71:19: +71:20 - _0 = const (); // scope 34 at $DIR/reference_prop.rs:+67:5: +72:6 - StorageDead(_53); // scope 35 at $DIR/reference_prop.rs:+72:5: +72:6 - StorageDead(_51); // scope 34 at $DIR/reference_prop.rs:+72:5: +72:6 - return; // scope 0 at $DIR/reference_prop.rs:+73:2: +73:2 + StorageDead(_56); // scope 36 at $DIR/reference_prop.rs:+71:18: +71:19 + StorageDead(_55); // scope 36 at $DIR/reference_prop.rs:+71:19: +71:20 +- _51 = const (); // scope 34 at $DIR/reference_prop.rs:+67:5: +72:6 + StorageDead(_54); // scope 35 at $DIR/reference_prop.rs:+72:5: +72:6 + StorageDead(_52); // scope 34 at $DIR/reference_prop.rs:+72:5: +72:6 +- StorageDead(_51); // scope 0 at $DIR/reference_prop.rs:+72:5: +72:6 +- StorageLive(_57); // scope 0 at $DIR/reference_prop.rs:+75:5: +81:6 + StorageLive(_58); // scope 37 at $DIR/reference_prop.rs:+76:13: +76:18 + _58 = const 5_usize; // scope 37 at $DIR/reference_prop.rs:+76:21: +76:28 +- StorageLive(_59); // scope 38 at $DIR/reference_prop.rs:+77:13: +77:14 +- _59 = &raw mut _58; // scope 38 at $DIR/reference_prop.rs:+77:17: +77:27 +- StorageLive(_60); // scope 39 at $DIR/reference_prop.rs:+78:13: +78:14 +- _60 = &_59; // scope 39 at $DIR/reference_prop.rs:+78:17: +78:19 + StorageLive(_61); // scope 40 at $DIR/reference_prop.rs:+79:13: +79:14 +- _61 = (*_59); // scope 40 at $DIR/reference_prop.rs:+79:17: +79:19 ++ _61 = _58; // scope 40 at $DIR/reference_prop.rs:+79:17: +79:19 + StorageLive(_62); // scope 41 at $DIR/reference_prop.rs:+80:9: +80:19 + StorageLive(_63); // scope 41 at $DIR/reference_prop.rs:+80:16: +80:18 + _63 = (); // scope 41 at $DIR/reference_prop.rs:+80:16: +80:18 + _62 = opaque::<()>(move _63) -> bb9; // scope 41 at $DIR/reference_prop.rs:+80:9: +80:19 + // mir::Constant + // + span: $DIR/reference_prop.rs:378:9: 378:15 + // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + } + + bb9: { + StorageDead(_63); // scope 41 at $DIR/reference_prop.rs:+80:18: +80:19 + StorageDead(_62); // scope 41 at $DIR/reference_prop.rs:+80:19: +80:20 +- _57 = const (); // scope 37 at $DIR/reference_prop.rs:+75:5: +81:6 + StorageDead(_61); // scope 40 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageDead(_60); // scope 39 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageDead(_59); // scope 38 at $DIR/reference_prop.rs:+81:5: +81:6 + StorageDead(_58); // scope 37 at $DIR/reference_prop.rs:+81:5: +81:6 +- StorageDead(_57); // scope 0 at $DIR/reference_prop.rs:+81:5: +81:6 + StorageLive(_64); // scope 42 at $DIR/reference_prop.rs:+85:13: +85:18 + _64 = const 5_usize; // scope 42 at $DIR/reference_prop.rs:+85:21: +85:28 +- StorageLive(_65); // scope 43 at $DIR/reference_prop.rs:+86:13: +86:18 +- _65 = &raw mut _64; // scope 43 at $DIR/reference_prop.rs:+86:21: +86:31 +- StorageLive(_66); // scope 44 at $DIR/reference_prop.rs:+87:13: +87:14 +- _66 = &mut _65; // scope 44 at $DIR/reference_prop.rs:+87:17: +87:23 + StorageLive(_67); // scope 45 at $DIR/reference_prop.rs:+88:13: +88:14 +- _67 = (*_65); // scope 45 at $DIR/reference_prop.rs:+88:17: +88:19 ++ _67 = _64; // scope 45 at $DIR/reference_prop.rs:+88:17: +88:19 + StorageLive(_68); // scope 46 at $DIR/reference_prop.rs:+89:9: +89:19 + StorageLive(_69); // scope 46 at $DIR/reference_prop.rs:+89:16: +89:18 + _69 = (); // scope 46 at $DIR/reference_prop.rs:+89:16: +89:18 + _68 = opaque::<()>(move _69) -> bb10; // scope 46 at $DIR/reference_prop.rs:+89:9: +89:19 + // mir::Constant + // + span: $DIR/reference_prop.rs:387:9: 387:15 + // + literal: Const { ty: fn(()) {opaque::<()>}, val: Value(<ZST>) } + } + + bb10: { + StorageDead(_69); // scope 46 at $DIR/reference_prop.rs:+89:18: +89:19 + StorageDead(_68); // scope 46 at $DIR/reference_prop.rs:+89:19: +89:20 + _0 = const (); // scope 42 at $DIR/reference_prop.rs:+84:5: +90:6 + StorageDead(_67); // scope 45 at $DIR/reference_prop.rs:+90:5: +90:6 +- StorageDead(_66); // scope 44 at $DIR/reference_prop.rs:+90:5: +90:6 +- StorageDead(_65); // scope 43 at $DIR/reference_prop.rs:+90:5: +90:6 + StorageDead(_64); // scope 42 at $DIR/reference_prop.rs:+90:5: +90:6 + return; // scope 0 at $DIR/reference_prop.rs:+91:2: +91:2 } } diff --git a/tests/mir-opt/reference_prop.rs b/tests/mir-opt/reference_prop.rs index 93f8d1df8e8..4083b45470b 100644 --- a/tests/mir-opt/reference_prop.rs +++ b/tests/mir-opt/reference_prop.rs @@ -33,16 +33,16 @@ fn reference_propagation<'a, T: Copy>(single: &'a T, mut multiple: &'a T) { let b = &a; let d = &b; let c = *b; // `b` is immutably borrowed, we know its value, but do not propagate it - opaque(()); + opaque(d); // prevent `d` from being removed. } // Propagation through a borrowed reference. { let a = 5_usize; let mut b = &a; - let d = &mut b; + let d = &raw mut b; let c = *b; // `b` is mutably borrowed, we cannot know its value. - opaque(()); + opaque(d); // prevent `d` from being removed. } // Propagation through an escaping borrow. @@ -80,6 +80,24 @@ fn reference_propagation<'a, T: Copy>(single: &'a T, mut multiple: &'a T) { let b = *a; // This should not be optimized. opaque(()); } + + // Fixed-point propagation through a borrowed reference. + { + let a = 5_usize; + let b = &a; + let d = &b; // first round promotes debuginfo for `d` + let c = *b; // second round propagates this dereference + opaque(()); + } + + // Fixed-point propagation through a borrowed reference. + { + let a = 5_usize; + let mut b = &a; + let d = &mut b; // first round promotes debuginfo for `d` + let c = *b; // second round propagates this dereference + opaque(()); + } } fn reference_propagation_mut<'a, T: Copy>(single: &'a mut T, mut multiple: &'a mut T) { @@ -108,16 +126,16 @@ fn reference_propagation_mut<'a, T: Copy>(single: &'a mut T, mut multiple: &'a m let b = &mut a; let d = &b; let c = *b; // `b` is immutably borrowed, we know its value, but cannot be removed. - opaque(()); + opaque(d); // prevent `d` from being removed. } // Propagation through a borrowed reference. { let mut a = 5_usize; let mut b = &mut a; - let d = &mut b; + let d = &raw mut b; let c = *b; // `b` is mutably borrowed, we cannot know its value. - opaque(()); + opaque(d); // prevent `d` from being removed. } // Propagation through an escaping borrow. @@ -155,6 +173,24 @@ fn reference_propagation_mut<'a, T: Copy>(single: &'a mut T, mut multiple: &'a m let b = *a; // This should not be optimized. opaque(()); } + + // Fixed-point propagation through a borrowed reference. + { + let mut a = 5_usize; + let b = &mut a; + let d = &b; // first round promotes debuginfo for `d` + let c = *b; // second round propagates this dereference + opaque(()); + } + + // Fixed-point propagation through a borrowed reference. + { + let mut a = 5_usize; + let mut b = &mut a; + let d = &mut b; // first round promotes debuginfo for `d` + let c = *b; // second round propagates this dereference + opaque(()); + } } fn reference_propagation_const_ptr<T: Copy>(single: *const T, mut multiple: *const T) { @@ -183,16 +219,16 @@ fn reference_propagation_const_ptr<T: Copy>(single: *const T, mut multiple: *con let b = &raw const a; let d = &b; let c = *b; // `b` is immutably borrowed, we know its value, but cannot be removed. - opaque(()); + opaque(d); // prevent `d` from being removed. } // Propagation through a borrowed reference. unsafe { let a = 5_usize; let mut b = &raw const a; - let d = &mut b; + let d = &raw mut b; let c = *b; // `b` is mutably borrowed, we cannot know its value. - opaque(()); + opaque(d); // prevent `d` from being removed. } // Propagation through an escaping borrow. @@ -239,6 +275,24 @@ fn reference_propagation_const_ptr<T: Copy>(single: *const T, mut multiple: *con let e = *c; opaque(()); } + + // Fixed-point propagation through a borrowed reference. + unsafe { + let a = 5_usize; + let b = &raw const a; + let d = &b; // first round promotes debuginfo for `d` + let c = *b; // second round propagates this dereference + opaque(()); + } + + // Fixed-point propagation through a borrowed reference. + unsafe { + let a = 5_usize; + let mut b = &raw const a; + let d = &mut b; // first round promotes debuginfo for `d` + let c = *b; // second round propagates this dereference + opaque(()); + } } fn reference_propagation_mut_ptr<T: Copy>(single: *mut T, mut multiple: *mut T) { @@ -267,16 +321,16 @@ fn reference_propagation_mut_ptr<T: Copy>(single: *mut T, mut multiple: *mut T) let b = &raw mut a; let d = &b; let c = *b; // `b` is immutably borrowed, we know its value, but cannot be removed. - opaque(()); + opaque(d); // prevent `d` from being removed. } // Propagation through a borrowed reference. unsafe { let mut a = 5_usize; let mut b = &raw mut a; - let d = &mut b; + let d = &raw mut b; let c = *b; // `b` is mutably borrowed, we cannot know its value. - opaque(()); + opaque(d); // prevent `d` from being removed. } // Propagation through an escaping borrow. @@ -314,6 +368,24 @@ fn reference_propagation_mut_ptr<T: Copy>(single: *mut T, mut multiple: *mut T) let b = *a; // This should not be optimized. opaque(()); } + + // Fixed-point propagation through a borrowed reference. + unsafe { + let mut a = 5_usize; + let b = &raw mut a; + let d = &b; // first round promotes debuginfo for `d` + let c = *b; // second round propagates this dereference + opaque(()); + } + + // Fixed-point propagation through a borrowed reference. + unsafe { + let mut a = 5_usize; + let mut b = &raw mut a; + let d = &mut b; // first round promotes debuginfo for `d` + let c = *b; // second round propagates this dereference + opaque(()); + } } #[custom_mir(dialect = "runtime", phase = "post-cleanup")] @@ -456,6 +528,40 @@ fn unique_with_copies() { unsafe { opaque(*y) }; } +fn debuginfo() { + struct T(u8); + + let ref_mut_u8 = &mut 5_u8; + let field = &T(0).0; + + // Verify that we don't emit `&*` in debuginfo. + let reborrow = &*ref_mut_u8; + + match Some(0) { + None => {} + Some(ref variant_field) => {} + } + + // `constant_index_from_end` and `subslice` should not be promoted, as their value depends + // on the slice length. + if let [_, ref constant_index, subslice @ .., ref constant_index_from_end] = &[6; 10][..] { + } + + let multiple_borrow = &&&mut T(6).0; +} + +fn many_debuginfo() { + let a = 0; + + // Verify that we do not ICE on deeply nested borrows. + let many_borrow = + &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& + &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& + &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& + &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& + &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&a; +} + fn main() { let mut x = 5_usize; let mut y = 7_usize; @@ -469,6 +575,8 @@ fn main() { maybe_dead(true); mut_raw_then_mut_shr(); unique_with_copies(); + debuginfo(); + many_debuginfo(); } // EMIT_MIR reference_prop.reference_propagation.ReferencePropagation.diff @@ -481,3 +589,4 @@ fn main() { // EMIT_MIR reference_prop.maybe_dead.ReferencePropagation.diff // EMIT_MIR reference_prop.mut_raw_then_mut_shr.ReferencePropagation.diff // EMIT_MIR reference_prop.unique_with_copies.ReferencePropagation.diff +// EMIT_MIR reference_prop.debuginfo.ReferencePropagation.diff diff --git a/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff b/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff index 2cda2409e80..b754aff4755 100644 --- a/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.unique_with_copies.ReferencePropagation.diff @@ -10,7 +10,8 @@ let _6: (); // in scope 0 at $DIR/reference_prop.rs:+9:14: +9:24 let mut _7: i32; // in scope 0 at $DIR/reference_prop.rs:+9:21: +9:23 scope 1 { - debug y => _1; // in scope 1 at $DIR/reference_prop.rs:+1:9: +1:10 +- debug y => _1; // in scope 1 at $DIR/reference_prop.rs:+1:9: +1:10 ++ debug y => _3; // in scope 1 at $DIR/reference_prop.rs:+1:9: +1:10 scope 5 { } } @@ -25,7 +26,7 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/reference_prop.rs:+1:9: +1:10 +- StorageLive(_1); // scope 0 at $DIR/reference_prop.rs:+1:9: +1:10 StorageLive(_2); // scope 0 at $DIR/reference_prop.rs:+2:13: +2:18 _2 = const 0_i32; // scope 0 at $DIR/reference_prop.rs:+2:21: +2:22 - StorageLive(_3); // scope 2 at $DIR/reference_prop.rs:+3:13: +3:14 @@ -35,14 +36,14 @@ _5 = (*_3); // scope 4 at $DIR/reference_prop.rs:+5:25: +5:27 _4 = opaque::<i32>(move _5) -> bb1; // scope 4 at $DIR/reference_prop.rs:+5:18: +5:28 // mir::Constant - // + span: $DIR/reference_prop.rs:452:18: 452:24 + // + span: $DIR/reference_prop.rs:524:18: 524:24 // + literal: Const { ty: fn(i32) {opaque::<i32>}, val: Value(<ZST>) } } bb1: { StorageDead(_5); // scope 4 at $DIR/reference_prop.rs:+5:27: +5:28 StorageDead(_4); // scope 3 at $DIR/reference_prop.rs:+5:30: +5:31 - _1 = _3; // scope 3 at $DIR/reference_prop.rs:+6:9: +6:10 +- _1 = _3; // scope 3 at $DIR/reference_prop.rs:+6:9: +6:10 - StorageDead(_3); // scope 2 at $DIR/reference_prop.rs:+7:5: +7:6 StorageDead(_2); // scope 0 at $DIR/reference_prop.rs:+7:5: +7:6 StorageLive(_6); // scope 1 at $DIR/reference_prop.rs:+9:5: +9:26 @@ -51,7 +52,7 @@ + _7 = (*_3); // scope 5 at $DIR/reference_prop.rs:+9:21: +9:23 _6 = opaque::<i32>(move _7) -> bb2; // scope 5 at $DIR/reference_prop.rs:+9:14: +9:24 // mir::Constant - // + span: $DIR/reference_prop.rs:456:14: 456:20 + // + span: $DIR/reference_prop.rs:528:14: 528:20 // + literal: Const { ty: fn(i32) {opaque::<i32>}, val: Value(<ZST>) } } @@ -59,7 +60,7 @@ StorageDead(_7); // scope 5 at $DIR/reference_prop.rs:+9:23: +9:24 StorageDead(_6); // scope 1 at $DIR/reference_prop.rs:+9:26: +9:27 _0 = const (); // scope 0 at $DIR/reference_prop.rs:+0:25: +10:2 - StorageDead(_1); // scope 0 at $DIR/reference_prop.rs:+10:1: +10:2 +- StorageDead(_1); // scope 0 at $DIR/reference_prop.rs:+10:1: +10:2 return; // scope 0 at $DIR/reference_prop.rs:+10:2: +10:2 } } diff --git a/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff b/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff index 7ad1ccf28a6..afdcf57815f 100644 --- a/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff +++ b/tests/mir-opt/slice_filter.variant_a-{closure#0}.DestinationPropagation.diff @@ -3,136 +3,79 @@ fn variant_a::{closure#0}(_1: &mut [closure@$DIR/slice_filter.rs:8:25: 8:39], _2: &&(usize, usize, usize, usize)) -> bool { let mut _0: bool; // return place in scope 0 at $DIR/slice_filter.rs:+0:40: +0:40 - let _3: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 - let _4: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 - let _5: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 - let _6: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 - let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:56 - let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:46 - let mut _9: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:41 - let mut _10: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46 - let _11: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:45: +0:46 - let mut _12: bool; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:56 - let mut _13: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:51 - let mut _14: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56 - let _15: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:55: +0:56 - let mut _16: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:76 - let mut _17: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:66 - let mut _18: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:61 - let mut _19: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66 - let _20: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:65: +0:66 - let mut _21: bool; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:76 - let mut _22: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:71 - let mut _23: &&usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 - let _24: &usize; // in scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 - let mut _25: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 - let mut _26: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 - let mut _27: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 - let mut _28: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _3: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:56 + let mut _4: bool; // in scope 0 at $DIR/slice_filter.rs:+0:40: +0:46 + let mut _5: bool; // in scope 0 at $DIR/slice_filter.rs:+0:50: +0:56 + let mut _6: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:76 + let mut _7: bool; // in scope 0 at $DIR/slice_filter.rs:+0:60: +0:66 + let mut _8: bool; // in scope 0 at $DIR/slice_filter.rs:+0:70: +0:76 + let mut _9: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _10: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _11: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 + let mut _12: &(usize, usize, usize, usize); // in scope 0 at $DIR/slice_filter.rs:+0:26: +0:38 scope 1 { -- debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28 -- debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31 -- debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34 -- debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37 -+ debug a => _20; // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28 -+ debug b => _15; // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31 -+ debug c => _11; // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34 -+ debug d => _24; // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37 + debug a => &((*_9).0: usize); // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28 + debug b => &((*_10).1: usize); // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31 + debug c => &((*_11).2: usize); // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34 + debug d => &((*_12).3: usize); // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37 scope 2 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:40: 8:46 - debug self => _9; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _10; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _29: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _30: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => &&((*_9).0: usize); // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => &&((*_11).2: usize); // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL scope 3 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL - debug self => _29; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _30; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _31: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _32: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => &((*_9).0: usize); // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => &((*_11).2: usize); // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _13: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _14: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL } } scope 4 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:60: 8:66 - debug self => _18; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _19; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _33: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _34: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => &&((*_11).2: usize); // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => &&((*_9).0: usize); // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL scope 5 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL - debug self => _33; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _34; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _35: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _36: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => &((*_11).2: usize); // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => &((*_9).0: usize); // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _15: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _16: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL } } scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:50: 8:56 - debug self => _13; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _14; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _37: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _38: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => &&((*_12).3: usize); // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => &&((*_10).1: usize); // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL - debug self => _37; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _38; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _39: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _40: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => &((*_12).3: usize); // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => &((*_10).1: usize); // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _17: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _18: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL } } scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:70: 8:76 - debug self => _22; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _23; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _41: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _42: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => &&((*_10).1: usize); // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => &&((*_12).3: usize); // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL - debug self => _41; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _42; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _43: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL - let mut _44: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug self => &((*_10).1: usize); // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + debug other => &((*_12).3: usize); // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _19: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + let mut _20: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL } } } bb0: { -- StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 -+ nop; // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 - _25 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 -- _3 = &((*_25).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 -- StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 -+ _20 = &((*_25).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 -+ nop; // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 - _26 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 -- _4 = &((*_26).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 -- StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 -+ _15 = &((*_26).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 -+ nop; // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 - _27 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 -- _5 = &((*_27).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 -- StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 -+ _11 = &((*_27).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 -+ nop; // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 - _28 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 -- _6 = &((*_28).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 -- StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 -+ _24 = &((*_28).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 + _9 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 + _10 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 + _11 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 + _12 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 +- StorageLive(_3); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + nop; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 - StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46 - StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 - StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 -- StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 -- _11 = _5; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 -- _29 = deref_copy _3; // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ nop; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 -+ nop; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 -+ _29 = deref_copy _20; // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL - _30 = deref_copy _11; // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageLive(_31); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - _31 = (*_29); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageLive(_32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - _32 = (*_30); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - _8 = Le(move _31, move _32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageDead(_32); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageDead(_31); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL -- StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 -+ nop; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 - StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 - StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 - switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + StorageLive(_4); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46 + StorageLive(_13); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + _13 = ((*_9).0: usize); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_14); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + _14 = ((*_11).2: usize); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + _4 = Le(move _13, move _14); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_14); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_13); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL + switchInt(move _4) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 } bb1: { @@ -141,127 +84,80 @@ } bb2: { -- StorageLive(_16); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 +- StorageLive(_6); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + nop; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 - StorageLive(_17); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66 - StorageLive(_18); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 - StorageLive(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 -- StorageLive(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 -- _20 = _3; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 -- _33 = deref_copy _5; // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ nop; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 -+ nop; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 -+ _33 = deref_copy _11; // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL - _34 = deref_copy _20; // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageLive(_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - _35 = (*_33); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageLive(_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - _36 = (*_34); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - _17 = Le(move _35, move _36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageDead(_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageDead(_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL -- StorageDead(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 -+ nop; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 - StorageDead(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 - StorageDead(_18); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 - switchInt(move _17) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66 + StorageLive(_15); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + _15 = ((*_11).2: usize); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_16); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + _16 = ((*_9).0: usize); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + _7 = Le(move _15, move _16); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_16); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_15); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL + switchInt(move _7) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 } bb3: { -- StorageDead(_16); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 -- StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 -- StorageDead(_6); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 -- StorageDead(_5); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 -- StorageDead(_4); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 -- StorageDead(_3); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_6); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_3); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 -+ nop; // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 -+ nop; // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 -+ nop; // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 -+ nop; // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 return; // scope 0 at $DIR/slice_filter.rs:+0:76: +0:76 } bb4: { -- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- StorageDead(_5); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + nop; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 - StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageDead(_4); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 goto -> bb2; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 } bb5: { -- StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56 +- StorageLive(_5); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56 + nop; // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56 - StorageLive(_13); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 - StorageLive(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 -- StorageLive(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 -- _15 = _4; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 -- _37 = deref_copy _6; // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ nop; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 -+ nop; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 -+ _37 = deref_copy _24; // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL - _38 = deref_copy _15; // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageLive(_39); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - _39 = (*_37); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageLive(_40); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - _40 = (*_38); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - _12 = Le(move _39, move _40); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageDead(_40); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageDead(_39); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL -- StorageDead(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 -+ nop; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 - StorageDead(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 - StorageDead(_13); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 -- _7 = move _12; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 -- StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + StorageLive(_17); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + _17 = ((*_12).3: usize); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_18); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + _18 = ((*_10).1: usize); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + _5 = Le(move _17, move _18); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_18); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_17); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _3 = move _5; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 +- StorageDead(_5); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 + nop; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 + nop; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 - StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 -- switchInt(move _7) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 -+ switchInt(move _12) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + StorageDead(_4); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- switchInt(move _3) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 ++ switchInt(move _5) -> [0: bb2, otherwise: bb1]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 } bb6: { -- _16 = const false; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 +- _6 = const false; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + _0 = const false; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 } bb7: { -- StorageLive(_21); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76 +- StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76 + nop; // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76 - StorageLive(_22); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 - StorageLive(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 -- StorageLive(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 -- _24 = _6; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 -- _41 = deref_copy _4; // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 -+ nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 -+ _41 = deref_copy _15; // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL - _42 = deref_copy _24; // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageLive(_43); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL - _43 = (*_41); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageLive(_44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL - _44 = (*_42); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL -- _21 = Le(move _43, move _44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ _0 = Le(move _43, move _44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageDead(_44); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageDead(_43); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL -- StorageDead(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 -+ nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 - StorageDead(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 - StorageDead(_22); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 -- _16 = move _21; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + StorageLive(_19); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + _19 = ((*_10).1: usize); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageLive(_20); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + _20 = ((*_12).3: usize); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _8 = Le(move _19, move _20); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _0 = Le(move _19, move _20); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_20); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL + StorageDead(_19); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _6 = move _8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 + nop; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 } bb8: { -- StorageDead(_21); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 + nop; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 - StorageDead(_17); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 -- _0 = move _16; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- _0 = move _6; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 + nop; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 goto -> bb3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:76 } diff --git a/tests/mir-opt/slice_filter.variant_a-{closure#0}.ReferencePropagation.diff b/tests/mir-opt/slice_filter.variant_a-{closure#0}.ReferencePropagation.diff index f6350b3812a..2534eeef432 100644 --- a/tests/mir-opt/slice_filter.variant_a-{closure#0}.ReferencePropagation.diff +++ b/tests/mir-opt/slice_filter.variant_a-{closure#0}.ReferencePropagation.diff @@ -38,54 +38,74 @@ let mut _49: &usize; // in scope 0 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _50: &usize; // in scope 0 at $SRC_DIR/core/src/cmp.rs:LL:COL scope 1 { - debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28 - debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31 - debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34 - debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37 +- debug a => _3; // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28 +- debug b => _4; // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31 +- debug c => _5; // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34 +- debug d => _6; // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37 ++ debug a => &((*_25).0: usize); // in scope 1 at $DIR/slice_filter.rs:+0:27: +0:28 ++ debug b => &((*_26).1: usize); // in scope 1 at $DIR/slice_filter.rs:+0:30: +0:31 ++ debug c => &((*_27).2: usize); // in scope 1 at $DIR/slice_filter.rs:+0:33: +0:34 ++ debug d => &((*_28).3: usize); // in scope 1 at $DIR/slice_filter.rs:+0:36: +0:37 scope 2 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:40: 8:46 - debug self => _9; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _10; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _9; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _10; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => &&((*_25).0: usize); // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => &&((*_27).2: usize); // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _29: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _30: &usize; // in scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL scope 3 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL - debug self => _29; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _30; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _29; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _30; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => &((*_25).0: usize); // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => &((*_27).2: usize); // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _33: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _34: usize; // in scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL } } scope 4 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:60: 8:66 - debug self => _18; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _19; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _18; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _19; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => &&((*_27).2: usize); // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => &&((*_25).0: usize); // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _35: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _36: &usize; // in scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL scope 5 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL - debug self => _35; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _36; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _35; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _36; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => &((*_27).2: usize); // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => &((*_25).0: usize); // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _39: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _40: usize; // in scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL } } scope 6 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:50: 8:56 - debug self => _13; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _14; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _13; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _14; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => &&((*_28).3: usize); // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => &&((*_26).1: usize); // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _41: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _42: &usize; // in scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL scope 7 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL - debug self => _41; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _42; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _41; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _42; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => &((*_28).3: usize); // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => &((*_26).1: usize); // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _45: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _46: usize; // in scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL } } scope 8 (inlined cmp::impls::<impl PartialOrd for &usize>::le) { // at $DIR/slice_filter.rs:8:70: 8:76 - debug self => _22; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _23; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _22; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _23; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => &&((*_26).1: usize); // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => &&((*_28).3: usize); // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _47: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _48: &usize; // in scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL scope 9 (inlined cmp::impls::<impl PartialOrd for usize>::le) { // at $SRC_DIR/core/src/cmp.rs:LL:COL - debug self => _47; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL - debug other => _48; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug self => _47; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- debug other => _48; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug self => &((*_26).1: usize); // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ debug other => &((*_28).3: usize); // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _51: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL let mut _52: usize; // in scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL } @@ -93,40 +113,40 @@ } bb0: { - StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 +- StorageLive(_3); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 _25 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 - _3 = &((*_25).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 - StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 +- _3 = &((*_25).0: usize); // scope 0 at $DIR/slice_filter.rs:+0:27: +0:28 +- StorageLive(_4); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 _26 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 - _4 = &((*_26).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 - StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 +- _4 = &((*_26).1: usize); // scope 0 at $DIR/slice_filter.rs:+0:30: +0:31 +- StorageLive(_5); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 _27 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 - _5 = &((*_27).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 - StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 +- _5 = &((*_27).2: usize); // scope 0 at $DIR/slice_filter.rs:+0:33: +0:34 +- StorageLive(_6); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 _28 = deref_copy (*_2); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 - _6 = &((*_28).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 +- _6 = &((*_28).3: usize); // scope 0 at $DIR/slice_filter.rs:+0:36: +0:37 StorageLive(_7); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 StorageLive(_8); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:46 - StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 - _9 = &_3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 - StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 - StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 - _11 = _5; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 - _10 = &_11; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 +- StorageLive(_9); // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 +- _9 = &_3; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:41 +- StorageLive(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 +- StorageLive(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 +- _11 = _5; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 +- _10 = &_11; // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 - _29 = deref_copy (*_9); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL - _30 = deref_copy (*_10); // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ _29 = deref_copy _3; // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ _30 = deref_copy _11; // scope 2 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageLive(_33); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - _33 = (*_29); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _33 = (*_29); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _33 = ((*_25).0: usize); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageLive(_34); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - _34 = (*_30); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _34 = (*_30); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _34 = ((*_27).2: usize); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL _8 = Le(move _33, move _34); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageDead(_34); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageDead(_33); // scope 3 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 - StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 - StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 +- StorageDead(_11); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 +- StorageDead(_10); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 +- StorageDead(_9); // scope 1 at $DIR/slice_filter.rs:+0:45: +0:46 switchInt(move _8) -> [0: bb4, otherwise: bb5]; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 } @@ -138,36 +158,36 @@ bb2: { StorageLive(_16); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 StorageLive(_17); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:66 - StorageLive(_18); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 - _18 = &_5; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 - StorageLive(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 - StorageLive(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 - _20 = _3; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 - _19 = &_20; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 +- StorageLive(_18); // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 +- _18 = &_5; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:61 +- StorageLive(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 +- StorageLive(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 +- _20 = _3; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 +- _19 = &_20; // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 - _35 = deref_copy (*_18); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL - _36 = deref_copy (*_19); // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ _35 = deref_copy _5; // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ _36 = deref_copy _20; // scope 4 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageLive(_39); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - _39 = (*_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _39 = (*_35); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _39 = ((*_27).2: usize); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageLive(_40); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - _40 = (*_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _40 = (*_36); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _40 = ((*_25).0: usize); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL _17 = Le(move _39, move _40); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageDead(_40); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageDead(_39); // scope 5 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageDead(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 - StorageDead(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 - StorageDead(_18); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 +- StorageDead(_20); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 +- StorageDead(_19); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 +- StorageDead(_18); // scope 1 at $DIR/slice_filter.rs:+0:65: +0:66 switchInt(move _17) -> [0: bb6, otherwise: bb7]; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 } bb3: { StorageDead(_16); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 StorageDead(_7); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 - StorageDead(_6); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 - StorageDead(_5); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 - StorageDead(_4); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 - StorageDead(_3); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_6); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_5); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_4); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_3); // scope 0 at $DIR/slice_filter.rs:+0:75: +0:76 return; // scope 0 at $DIR/slice_filter.rs:+0:76: +0:76 } @@ -180,26 +200,26 @@ bb5: { StorageLive(_12); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:56 - StorageLive(_13); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 - _13 = &_6; // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 - StorageLive(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 - StorageLive(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 - _15 = _4; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 - _14 = &_15; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- StorageLive(_13); // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 +- _13 = &_6; // scope 1 at $DIR/slice_filter.rs:+0:50: +0:51 +- StorageLive(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- StorageLive(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- _15 = _4; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- _14 = &_15; // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 - _41 = deref_copy (*_13); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL - _42 = deref_copy (*_14); // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ _41 = deref_copy _6; // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ _42 = deref_copy _15; // scope 6 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageLive(_45); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - _45 = (*_41); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _45 = (*_41); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _45 = ((*_28).3: usize); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageLive(_46); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - _46 = (*_42); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _46 = (*_42); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _46 = ((*_26).1: usize); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL _12 = Le(move _45, move _46); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageDead(_46); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageDead(_45); // scope 7 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageDead(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 - StorageDead(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 - StorageDead(_13); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- StorageDead(_15); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- StorageDead(_14); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 +- StorageDead(_13); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 _7 = move _12; // scope 1 at $DIR/slice_filter.rs:+0:40: +0:56 StorageDead(_12); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 StorageDead(_8); // scope 1 at $DIR/slice_filter.rs:+0:55: +0:56 @@ -213,26 +233,26 @@ bb7: { StorageLive(_21); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:76 - StorageLive(_22); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 - _22 = &_4; // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 - StorageLive(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 - StorageLive(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 - _24 = _6; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 - _23 = &_24; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageLive(_22); // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 +- _22 = &_4; // scope 1 at $DIR/slice_filter.rs:+0:70: +0:71 +- StorageLive(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageLive(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- _24 = _6; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- _23 = &_24; // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 - _47 = deref_copy (*_22); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL - _48 = deref_copy (*_23); // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ _47 = deref_copy _4; // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL -+ _48 = deref_copy _24; // scope 8 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageLive(_51); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL - _51 = (*_47); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _51 = (*_47); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _51 = ((*_26).1: usize); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageLive(_52); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL - _52 = (*_48); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL +- _52 = (*_48); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL ++ _52 = ((*_28).3: usize); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL _21 = Le(move _51, move _52); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageDead(_52); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL StorageDead(_51); // scope 9 at $SRC_DIR/core/src/cmp.rs:LL:COL - StorageDead(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 - StorageDead(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 - StorageDead(_22); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_24); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_23); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 +- StorageDead(_22); // scope 1 at $DIR/slice_filter.rs:+0:75: +0:76 _16 = move _21; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 goto -> bb8; // scope 1 at $DIR/slice_filter.rs:+0:60: +0:76 } diff --git a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir index 2af864998cb..4b2a16b50b4 100644 --- a/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir +++ b/tests/mir-opt/uninhabited_enum.process_void.SimplifyLocals-final.after.mir @@ -3,16 +3,13 @@ fn process_void(_1: *const Void) -> () { debug input => _1; // in scope 0 at $DIR/uninhabited_enum.rs:+0:21: +0:26 let mut _0: (); // return place in scope 0 at $DIR/uninhabited_enum.rs:+0:41: +0:41 - let _2: &Void; // in scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14 scope 1 { - debug _input => _2; // in scope 1 at $DIR/uninhabited_enum.rs:+1:8: +1:14 + debug _input => _1; // in scope 1 at $DIR/uninhabited_enum.rs:+1:8: +1:14 } scope 2 { } bb0: { - StorageLive(_2); // scope 0 at $DIR/uninhabited_enum.rs:+1:8: +1:14 - StorageDead(_2); // scope 0 at $DIR/uninhabited_enum.rs:+4:1: +4:2 return; // scope 0 at $DIR/uninhabited_enum.rs:+4:2: +4:2 } } diff --git a/tests/run-make-fulldeps/obtain-borrowck/driver.rs b/tests/run-make-fulldeps/obtain-borrowck/driver.rs index 7bd7bb7c1ea..d342b2ff6d9 100644 --- a/tests/run-make-fulldeps/obtain-borrowck/driver.rs +++ b/tests/run-make-fulldeps/obtain-borrowck/driver.rs @@ -24,8 +24,8 @@ use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; use rustc_interface::interface::Compiler; use rustc_interface::{Config, Queries}; -use rustc_middle::ty::query::query_values::mir_borrowck; -use rustc_middle::ty::query::{ExternProviders, Providers}; +use rustc_middle::query::queries::mir_borrowck::ProvidedValue; +use rustc_middle::query::{ExternProviders, Providers}; use rustc_middle::ty::TyCtxt; use rustc_session::Session; use std::cell::RefCell; @@ -126,7 +126,7 @@ thread_local! { RefCell::new(HashMap::new()); } -fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> mir_borrowck<'tcx> { +fn mir_borrowck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> ProvidedValue<'tcx> { let body_with_facts = rustc_borrowck::consumers::get_body_with_borrowck_facts(tcx, def_id); // SAFETY: The reader casts the 'static lifetime to 'tcx before using it. let body_with_facts: BodyWithBorrowckFacts<'static> = diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/Makefile b/tests/run-make/CURRENT_RUSTC_VERSION/Makefile new file mode 100644 index 00000000000..7940dae207b --- /dev/null +++ b/tests/run-make/CURRENT_RUSTC_VERSION/Makefile @@ -0,0 +1,6 @@ +include ../tools.mk + +all: + $(RUSTC) --emit=metadata --crate-type lib stable.rs + $(RUSTC) --emit=metadata --extern stable=$(TMPDIR)/libstable.rmeta main.rs 2>&1 >/dev/null \ + | $(CGREP) -e "stable since $$(cat $(S)/src/version)(-[a-zA-Z]+)?" diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/main.rs b/tests/run-make/CURRENT_RUSTC_VERSION/main.rs new file mode 100644 index 00000000000..466aaa82bd4 --- /dev/null +++ b/tests/run-make/CURRENT_RUSTC_VERSION/main.rs @@ -0,0 +1,4 @@ +#![feature(foo)] +extern crate stable; + +fn main() {} diff --git a/tests/run-make/CURRENT_RUSTC_VERSION/stable.rs b/tests/run-make/CURRENT_RUSTC_VERSION/stable.rs new file mode 100644 index 00000000000..2fd09aded60 --- /dev/null +++ b/tests/run-make/CURRENT_RUSTC_VERSION/stable.rs @@ -0,0 +1,5 @@ +#![feature(staged_api)] +#![stable(since = "1.0.0", feature = "rust1")] + +#[stable(since = "CURRENT_RUSTC_VERSION", feature = "foo")] +pub fn foo() {} diff --git a/tests/run-make/coverage-llvmir/filecheck.testprog.txt b/tests/run-make/coverage-llvmir/filecheck.testprog.txt index c943261d799..b3a8808df05 100644 --- a/tests/run-make/coverage-llvmir/filecheck.testprog.txt +++ b/tests/run-make/coverage-llvmir/filecheck.testprog.txt @@ -36,7 +36,7 @@ CHECK-SAME: section "llvm.metadata" CHECK: [[DEFINE_INTERNAL]] { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} { CHECK-NEXT: start: CHECK-NOT: [[DEFINE_INTERNAL]] -CHECK: %pgocount = load i64, {{i64\*|ptr}} +CHECK: atomicrmw add ptr CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, CHECK: declare void @llvm.instrprof.increment({{i8\*|ptr}}, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]] diff --git a/tests/run-make/debugger-visualizer-dep-info/Makefile b/tests/run-make/debugger-visualizer-dep-info/Makefile new file mode 100644 index 00000000000..0877998a74f --- /dev/null +++ b/tests/run-make/debugger-visualizer-dep-info/Makefile @@ -0,0 +1,9 @@ +include ../tools.mk + +# This test makes sure that files referenced via #[debugger_visualizer] are +# included in `--emit dep-info` output. + +all: + $(RUSTC) --emit dep-info main.rs + $(CGREP) "foo.py" < $(TMPDIR)/main.d + $(CGREP) "my_visualizers/bar.natvis" < $(TMPDIR)/main.d diff --git a/tests/run-make/debugger-visualizer-dep-info/foo.py b/tests/run-make/debugger-visualizer-dep-info/foo.py new file mode 100644 index 00000000000..1bb8bf6d7fd --- /dev/null +++ b/tests/run-make/debugger-visualizer-dep-info/foo.py @@ -0,0 +1 @@ +# empty diff --git a/tests/run-make/debugger-visualizer-dep-info/main.rs b/tests/run-make/debugger-visualizer-dep-info/main.rs new file mode 100644 index 00000000000..3aede2215ea --- /dev/null +++ b/tests/run-make/debugger-visualizer-dep-info/main.rs @@ -0,0 +1,12 @@ +#![debugger_visualizer(gdb_script_file = "foo.py")] + +fn main() { + const _UNUSED: u32 = { + mod inner { + #![debugger_visualizer(natvis_file = "my_visualizers/bar.natvis")] + pub const XYZ: u32 = 123; + } + + inner::XYZ + 1 + }; +} diff --git a/tests/run-make/debugger-visualizer-dep-info/my_visualizers/bar.natvis b/tests/run-make/debugger-visualizer-dep-info/my_visualizers/bar.natvis new file mode 100644 index 00000000000..c341a403902 --- /dev/null +++ b/tests/run-make/debugger-visualizer-dep-info/my_visualizers/bar.natvis @@ -0,0 +1 @@ +<!-- empty --> diff --git a/tests/run-make/incremental-debugger-visualizer/Makefile b/tests/run-make/incremental-debugger-visualizer/Makefile new file mode 100644 index 00000000000..8cfe41597ad --- /dev/null +++ b/tests/run-make/incremental-debugger-visualizer/Makefile @@ -0,0 +1,49 @@ +include ../tools.mk + +# This test makes sure that changes to files referenced via #[debugger_visualizer] +# are picked up when compiling incrementally. + +# We have to copy the source to $(TMPDIR) because Github CI mounts the source +# directory as readonly. We need to apply modifications to some of the source +# file. +SRC_DIR := $(TMPDIR)/src +INCR_CACHE_DIR := $(TMPDIR)/incremental + +all: + rm -rf $(TMPDIR)/* + mkdir $(SRC_DIR) + cp ./foo.rs $(SRC_DIR) + echo "GDB script v1" > $(SRC_DIR)/foo.py + echo "Natvis v1" > $(SRC_DIR)/foo.natvis + $(RUSTC) $(SRC_DIR)/foo.rs \ + --crate-type=rlib \ + --emit metadata \ + -C incremental=$(INCR_CACHE_DIR) \ + -Z incremental-verify-ich + $(CGREP) "GDB script v1" < $(TMPDIR)/libfoo.rmeta + $(CGREP) "Natvis v1" < $(TMPDIR)/libfoo.rmeta + + # Change only the GDB script and check that the change has been picked up + echo "GDB script v2" > $(SRC_DIR)/foo.py + $(RUSTC) $(SRC_DIR)/foo.rs \ + --crate-type=rlib \ + --emit metadata \ + -C incremental=$(INCR_CACHE_DIR) \ + -Z incremental-verify-ich + + $(CGREP) "GDB script v2" < $(TMPDIR)/libfoo.rmeta + $(CGREP) -v "GDB script v1" < $(TMPDIR)/libfoo.rmeta + $(CGREP) "Natvis v1" < $(TMPDIR)/libfoo.rmeta + + # Now change the Natvis version and check that the change has been picked up + echo "Natvis v2" > $(SRC_DIR)/foo.natvis + $(RUSTC) $(SRC_DIR)/foo.rs \ + --crate-type=rlib \ + --emit metadata \ + -C incremental=$(INCR_CACHE_DIR) \ + -Z incremental-verify-ich + + $(CGREP) "GDB script v2" < $(TMPDIR)/libfoo.rmeta + $(CGREP) -v "GDB script v1" < $(TMPDIR)/libfoo.rmeta + $(CGREP) "Natvis v2" < $(TMPDIR)/libfoo.rmeta + $(CGREP) -v "Natvis v1" < $(TMPDIR)/libfoo.rmeta diff --git a/tests/run-make/incremental-debugger-visualizer/foo.rs b/tests/run-make/incremental-debugger-visualizer/foo.rs new file mode 100644 index 00000000000..8daa36a12d3 --- /dev/null +++ b/tests/run-make/incremental-debugger-visualizer/foo.rs @@ -0,0 +1,6 @@ +#![debugger_visualizer(natvis_file = "./foo.natvis")] +#![debugger_visualizer(gdb_script_file = "./foo.py")] + +pub struct Foo { + pub x: u32, +} diff --git a/tests/run-make/print-native-static-libs/Makefile b/tests/run-make/print-native-static-libs/Makefile new file mode 100644 index 00000000000..98e72d7696f --- /dev/null +++ b/tests/run-make/print-native-static-libs/Makefile @@ -0,0 +1,15 @@ +include ../tools.mk + +# ignore-cross-compile +# ignore-wasm + +all: + $(RUSTC) --crate-type rlib -lbar_cli bar.rs + $(RUSTC) foo.rs -lfoo_cli --crate-type staticlib --print native-static-libs 2>&1 \ + | grep 'note: native-static-libs: ' \ + | sed 's/note: native-static-libs: \(.*\)/\1/' > $(TMPDIR)/libs.txt + + cat $(TMPDIR)/libs.txt | grep -F "glib-2.0" # in bar.rs + cat $(TMPDIR)/libs.txt | grep -F "systemd" # in foo.rs + cat $(TMPDIR)/libs.txt | grep -F "bar_cli" + cat $(TMPDIR)/libs.txt | grep -F "foo_cli" diff --git a/tests/run-make/print-native-static-libs/bar.rs b/tests/run-make/print-native-static-libs/bar.rs new file mode 100644 index 00000000000..a563bbc2a22 --- /dev/null +++ b/tests/run-make/print-native-static-libs/bar.rs @@ -0,0 +1,13 @@ +#[no_mangle] +pub extern "C" fn my_bar_add(left: i32, right: i32) -> i32 { + // Obviously makes no sense but... + unsafe { + g_free(std::ptr::null_mut()); + } + left + right +} + +#[link(name = "glib-2.0")] +extern "C" { + fn g_free(p: *mut ()); +} diff --git a/tests/run-make/print-native-static-libs/foo.rs b/tests/run-make/print-native-static-libs/foo.rs new file mode 100644 index 00000000000..6acaee20ed4 --- /dev/null +++ b/tests/run-make/print-native-static-libs/foo.rs @@ -0,0 +1,15 @@ +extern crate bar; + +#[no_mangle] +pub extern "C" fn my_foo_add(left: i32, right: i32) -> i32 { + // Obviously makes no sense but... + unsafe { + init(std::ptr::null_mut()); + } + bar::my_bar_add(left, right) +} + +#[link(name = "systemd")] +extern "C" { + fn init(p: *mut ()); +} diff --git a/tests/run-make/short-ice/Makefile b/tests/run-make/short-ice/Makefile new file mode 100644 index 00000000000..4f33d590237 --- /dev/null +++ b/tests/run-make/short-ice/Makefile @@ -0,0 +1,9 @@ +include ../tools.mk + +# ignore-windows + +export RUSTC := $(RUSTC_ORIGINAL) +export TMPDIR := $(TMPDIR) + +all: + bash check.sh diff --git a/tests/run-make/short-ice/check.sh b/tests/run-make/short-ice/check.sh new file mode 100644 index 00000000000..96cd8fe86bc --- /dev/null +++ b/tests/run-make/short-ice/check.sh @@ -0,0 +1,36 @@ +#!/bin/sh + +RUST_BACKTRACE=1 $RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-1.log 2>&1 +RUST_BACKTRACE=full $RUSTC src/lib.rs -Z treat-err-as-bug=1 1>$TMPDIR/rust-test-2.log 2>&1 + +short=$(cat $TMPDIR/rust-test-1.log | wc -l) +full=$(cat $TMPDIR/rust-test-2.log | wc -l) +rustc_query_count=$(cat $TMPDIR/rust-test-1.log | grep rustc_query_ | wc -l) +rustc_query_count_full=$(cat $TMPDIR/rust-test-2.log | grep rustc_query_ | wc -l) + +begin_count=$(cat $TMPDIR/rust-test-2.log | grep __rust_begin_short_backtrace | wc -l) +end_count=$(cat $TMPDIR/rust-test-2.log | grep __rust_end_short_backtrace | wc -l) + +cat $TMPDIR/rust-test-1.log +echo "=====================" +cat $TMPDIR/rust-test-2.log +echo "=====================" + +echo "short backtrace: $short" +echo "full backtrace: $full" +echo "begin_count: $begin_count" +echo "end_count : $end_count" +echo "rustc_query_count: $rustc_query_count" +echo "rustc_query_count_full: $rustc_query_count_full" + +## backtraces to vary a bit depending on platform and configuration options, +## here we make sure that the short backtrace of rustc_query is shorter than the full, +## and marks are in pairs. +if [ $short -lt $full ] && + [ $begin_count -eq $end_count ] && + [ $(($rustc_query_count + 10)) -lt $rustc_query_count_full ] && + [ $rustc_query_count_full -gt 10 ]; then + exit 0 +else + exit 1 +fi diff --git a/tests/run-make/short-ice/src/lib.rs b/tests/run-make/short-ice/src/lib.rs new file mode 100644 index 00000000000..b23b7f830d7 --- /dev/null +++ b/tests/run-make/short-ice/src/lib.rs @@ -0,0 +1,7 @@ +fn func(s: &str) { + println!("{}", s); +} + +fn main() { + func(1); +} diff --git a/tests/rustdoc-gui/anchors.goml b/tests/rustdoc-gui/anchors.goml index 0904aa90e1b..e9b77296917 100644 --- a/tests/rustdoc-gui/anchors.goml +++ b/tests/rustdoc-gui/anchors.goml @@ -75,35 +75,35 @@ call-function: ( "check-colors", { "theme": "ayu", - "main_color": "rgb(197, 197, 197)", - "title_color": "rgb(255, 255, 255)", - "main_heading_color": "rgb(255, 255, 255)", - "main_heading_type_color": "rgb(255, 160, 165)", - "src_link_color": "rgb(57, 175, 215)", - "sidebar_link_color": "rgb(83, 177, 219)", + "main_color": "#c5c5c5", + "title_color": "#fff", + "main_heading_color": "#fff", + "main_heading_type_color": "#ffa0a5", + "src_link_color": "#39afd7", + "sidebar_link_color": "#53b1db", }, ) call-function: ( "check-colors", { "theme": "dark", - "main_color": "rgb(221, 221, 221)", - "title_color": "rgb(221, 221, 221)", - "main_heading_color": "rgb(221, 221, 221)", - "main_heading_type_color": "rgb(45, 191, 184)", - "src_link_color": "rgb(210, 153, 29)", - "sidebar_link_color": "rgb(253, 191, 53)", + "main_color": "#ddd", + "title_color": "#ddd", + "main_heading_color": "#ddd", + "main_heading_type_color": "#2dbfb8", + "src_link_color": "#d2991d", + "sidebar_link_color": "#fdbf35", }, ) call-function: ( "check-colors", { "theme": "light", - "main_color": "rgb(0, 0, 0)", - "title_color": "rgb(0, 0, 0)", - "main_heading_color": "rgb(0, 0, 0)", - "main_heading_type_color": "rgb(173, 55, 138)", - "src_link_color": "rgb(56, 115, 173)", - "sidebar_link_color": "rgb(53, 109, 164)", + "main_color": "black", + "title_color": "black", + "main_heading_color": "black", + "main_heading_type_color": "#ad378a", + "src_link_color": "#3873ad", + "sidebar_link_color": "#356da4", }, ) diff --git a/tests/rustdoc-gui/codeblock-tooltip.goml b/tests/rustdoc-gui/codeblock-tooltip.goml index 2ed0579d314..e1c81ed79e4 100644 --- a/tests/rustdoc-gui/codeblock-tooltip.goml +++ b/tests/rustdoc-gui/codeblock-tooltip.goml @@ -109,19 +109,19 @@ define-function: ( call-function: ("check-colors", { "theme": "ayu", - "background": "rgb(15, 20, 25)", - "color": "rgb(197, 197, 197)", - "border": "rgb(92, 103, 115)", + "background": "#0f1419", + "color": "#c5c5c5", + "border": "#5c6773", }) call-function: ("check-colors", { "theme": "dark", - "background": "rgb(53, 53, 53)", - "color": "rgb(221, 221, 221)", - "border": "rgb(224, 224, 224)", + "background": "#353535", + "color": "#ddd", + "border": "#e0e0e0", }) call-function: ("check-colors", { "theme": "light", - "background": "rgb(255, 255, 255)", - "color": "rgb(0, 0, 0)", - "border": "rgb(224, 224, 224)", + "background": "white", + "color": "black", + "border": "#e0e0e0", }) diff --git a/tests/rustdoc-gui/scrape-examples-color.goml b/tests/rustdoc-gui/scrape-examples-color.goml index 8ddb06fccfc..0052d18dc56 100644 --- a/tests/rustdoc-gui/scrape-examples-color.goml +++ b/tests/rustdoc-gui/scrape-examples-color.goml @@ -33,30 +33,30 @@ define-function: ( call-function: ("check-colors", { "theme": "ayu", - "highlight": "rgb(91, 59, 1)", - "highlight_focus": "rgb(124, 75, 15)", - "help_border": "rgb(170, 170, 170)", - "help_color": "rgb(238, 238, 238)", - "help_hover_border": "rgb(255, 255, 255)", - "help_hover_color": "rgb(255, 255, 255)", + "highlight": "#5b3b01", + "highlight_focus": "#7c4b0f", + "help_border": "#aaa", + "help_color": "#eee", + "help_hover_border": "#fff", + "help_hover_color": "#fff", }) call-function: ("check-colors", { "theme": "dark", - "highlight": "rgb(91, 59, 1)", - "highlight_focus": "rgb(124, 75, 15)", - "help_border": "rgb(170, 170, 170)", - "help_color": "rgb(238, 238, 238)", - "help_hover_border": "rgb(255, 255, 255)", - "help_hover_color": "rgb(255, 255, 255)", + "highlight": "#5b3b01", + "highlight_focus": "#7c4b0f", + "help_border": "#aaa", + "help_color": "#eee", + "help_hover_border": "#fff", + "help_hover_color": "#fff", }) call-function: ("check-colors", { "theme": "light", - "highlight": "rgb(252, 255, 214)", - "highlight_focus": "rgb(246, 253, 176)", - "help_border": "rgb(85, 85, 85)", - "help_color": "rgb(51, 51, 51)", - "help_hover_border": "rgb(0, 0, 0)", - "help_hover_color": "rgb(0, 0, 0)", + "highlight": "#fcffd6", + "highlight_focus": "#f6fdb0", + "help_border": "#555", + "help_color": "#333", + "help_hover_border": "#000", + "help_hover_color": "#000", }) // Now testing the top and bottom background in case there is only one scraped examples. @@ -81,16 +81,16 @@ define-function: ( call-function: ("check-background", { "theme": "ayu", - "background_color_start": "rgb(15, 20, 25)", + "background_color_start": "rgba(15, 20, 25, 1)", "background_color_end": "rgba(15, 20, 25, 0)", }) call-function: ("check-background", { "theme": "dark", - "background_color_start": "rgb(53, 53, 53)", + "background_color_start": "rgba(53, 53, 53, 1)", "background_color_end": "rgba(53, 53, 53, 0)", }) call-function: ("check-background", { "theme": "light", - "background_color_start": "rgb(255, 255, 255)", + "background_color_start": "rgba(255, 255, 255, 1)", "background_color_end": "rgba(255, 255, 255, 0)", }) diff --git a/tests/rustdoc-gui/search-result-color.goml b/tests/rustdoc-gui/search-result-color.goml index da46a90df90..90f7160b724 100644 --- a/tests/rustdoc-gui/search-result-color.goml +++ b/tests/rustdoc-gui/search-result-color.goml @@ -47,89 +47,89 @@ reload: wait-for: "#search-tabs" assert-css: ( "#search-tabs > button > .count", - {"color": "rgb(136, 136, 136)"}, + {"color": "#888"}, ALL, ) assert-css: ( "//*[@class='desc'][text()='Just a normal struct.']", - {"color": "rgb(197, 197, 197)"}, + {"color": "#c5c5c5"}, ) assert-css: ( "//*[@class='result-name']/*[text()='test_docs::']", - {"color": "rgb(0, 150, 207)"}, + {"color": "#0096cf"}, ) // Checking the color of the bottom border. assert-css: ( ".search-results > a", - {"border-bottom-color": "rgba(170, 170, 170, 0.2)"} + {"border-bottom-color": "#aaa3"} ) // Checking the color of "keyword" text. assert-css: ( "//*[@class='result-name']//*[text()='(keyword)']", - {"color": "rgb(120, 135, 151)"}, + {"color": "#788797"}, ) -store-value: (entry_color, "rgb(0, 150, 207)") // color of the search entry -store-value: (hover_entry_color, "rgb(255, 255, 255)") // color of the hovered/focused search entry -store-value: (background_color, "rgba(0, 0, 0, 0)") // background color -store-value: (hover_background_color, "rgb(60, 60, 60)") // hover background color +store-value: (entry_color, "#0096cf") // color of the search entry +store-value: (hover_entry_color, "#fff") // color of the hovered/focused search entry +store-value: (background_color, "transparent") // background color +store-value: (hover_background_color, "#3c3c3c") // hover background color call-function: ( "check-result-color", ( "keyword", // item kind - "rgb(57, 175, 215)", // color of item kind - "rgb(57, 175, 215)", // color of hovered/focused item kind + "#39afd7", // color of item kind + "#39afd7", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "struct", // item kind - "rgb(255, 160, 165)", // color of item kind - "rgb(255, 160, 165)", // color of hovered/focused item kind + "#ffa0a5", // color of item kind + "#ffa0a5", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "associatedtype", // item kind - "rgb(57, 175, 215)", // color of item kind - "rgb(57, 175, 215)", // color of hovered/focused item kind + "#39afd7", // color of item kind + "#39afd7", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "tymethod", // item kind - "rgb(253, 214, 135)", // color of item kind - "rgb(253, 214, 135)", // color of hovered/focused item kind + "#fdd687", // color of item kind + "#fdd687", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "method", // item kind - "rgb(253, 214, 135)", // color of item kind - "rgb(253, 214, 135)", // color of hovered/focused item kind + "#fdd687", // color of item kind + "#fdd687", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "structfield", // item kind - "rgb(0, 150, 207)", // color of item kind - "rgb(255, 255, 255)", // color of hovered/focused item kind + "#0096cf", // color of item kind + "#fff", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "macro", // item kind - "rgb(163, 122, 204)", // color of item kind - "rgb(163, 122, 204)", // color of hovered/focused item kind + "#a37acc", // color of item kind + "#a37acc", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "fn", // item kind - "rgb(253, 214, 135)", // color of item kind - "rgb(253, 214, 135)", // color of hovered/focused item kind + "#fdd687", // color of item kind + "#fdd687", // color of hovered/focused item kind ), ) @@ -138,7 +138,7 @@ move-cursor-to: ".search-input" focus: ".search-input" // To ensure the `<a>` container isnt focus or hover. assert-css: ( "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", - {"color": "rgb(0, 150, 207)", "background-color": "rgba(0, 0, 0, 0)"}, + {"color": "#0096cf", "background-color": "transparent"}, ALL, ) @@ -146,11 +146,11 @@ assert-css: ( move-cursor-to: "//*[@class='desc'][text()='Just a normal struct.']" assert-css: ( "//*[@class='result-name']/*[text()='test_docs::']", - {"color": "rgb(255, 255, 255)"}, + {"color": "#fff"}, ) assert-css: ( "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", - {"color": "rgb(255, 255, 255)", "background-color": "rgb(60, 60, 60)"}, + {"color": "#fff", "background-color": "rgb(60, 60, 60)"}, ) // Dark theme @@ -164,89 +164,89 @@ reload: wait-for: "#search-tabs" assert-css: ( "#search-tabs > button > .count", - {"color": "rgb(136, 136, 136)"}, + {"color": "#888"}, ALL, ) assert-css: ( "//*[@class='desc'][text()='Just a normal struct.']", - {"color": "rgb(221, 221, 221)"}, + {"color": "#ddd"}, ) assert-css: ( "//*[@class='result-name']/*[text()='test_docs::']", - {"color": "rgb(221, 221, 221)"}, + {"color": "#ddd"}, ) // Checking the color of the bottom border. assert-css: ( ".search-results > a", - {"border-bottom-color": "rgba(170, 170, 170, 0.2)"} + {"border-bottom-color": "#aaa3"} ) // Checking the color for "keyword" text. assert-css: ( "//*[@class='result-name']//*[text()='(keyword)']", - {"color": "rgb(221, 221, 221)"}, + {"color": "#ddd"}, ) -store-value: (entry_color, "rgb(221, 221, 221)") // color of the search entry -store-value: (hover_entry_color, "rgb(221, 221, 221)") // color of the hovered/focused search entry -store-value: (background_color, "rgba(0, 0, 0, 0)") // background color -store-value: (hover_background_color, "rgb(97, 97, 97)") // hover background color +store-value: (entry_color, "#ddd") // color of the search entry +store-value: (hover_entry_color, "#ddd") // color of the hovered/focused search entry +store-value: (background_color, "transparent") // background color +store-value: (hover_background_color, "#616161") // hover background color call-function: ( "check-result-color", ( "keyword", // item kind - "rgb(210, 153, 29)", // color of item kind - "rgb(210, 153, 29)", // color of hovered/focused item kind + "#d2991d", // color of item kind + "#d2991d", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "struct", // item kind - "rgb(45, 191, 184)", // color of item kind - "rgb(45, 191, 184)", // color of hovered/focused item kind + "#2dbfb8", // color of item kind + "#2dbfb8", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "associatedtype", // item kind - "rgb(210, 153, 29)", // color of item kind - "rgb(210, 153, 29)", // color of hovered/focused item kind + "#d2991d", // color of item kind + "#d2991d", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "tymethod", // item kind - "rgb(43, 171, 99)", // color of item kind - "rgb(43, 171, 99)", // color of hovered/focused item kind + "#2bab63", // color of item kind + "#2bab63", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "method", // item kind - "rgb(43, 171, 99)", // color of item kind - "rgb(43, 171, 99)", // color of hovered/focused item kind + "#2bab63", // color of item kind + "#2bab63", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "structfield", // item kind - "rgb(221, 221, 221)", // color of item kind - "rgb(221, 221, 221)", // color of hovered/focused item kind + "#ddd", // color of item kind + "#ddd", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "macro", // item kind - "rgb(9, 189, 0)", // color of item kind - "rgb(9, 189, 0)", // color of hovered/focused item kind + "#09bd00", // color of item kind + "#09bd00", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "fn", // item kind - "rgb(43, 171, 99)", // color of item kind - "rgb(43, 171, 99)", // color of hovered/focused item kind + "#2bab63", // color of item kind + "#2bab63", // color of hovered/focused item kind ), ) @@ -255,7 +255,7 @@ move-cursor-to: ".search-input" focus: ".search-input" // To ensure the `<a>` container isnt focus or hover. assert-css: ( "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", - {"color": "rgb(221, 221, 221)", "background-color": "rgba(0, 0, 0, 0)"}, + {"color": "#ddd", "background-color": "transparent"}, ) // Light theme @@ -266,89 +266,89 @@ reload: wait-for: "#search-tabs" assert-css: ( "#search-tabs > button > .count", - {"color": "rgb(136, 136, 136)"}, + {"color": "#888"}, ALL, ) assert-css: ( "//*[@class='desc'][text()='Just a normal struct.']", - {"color": "rgb(0, 0, 0)"}, + {"color": "#000"}, ) assert-css: ( "//*[@class='result-name']/*[text()='test_docs::']", - {"color": "rgb(0, 0, 0)"}, + {"color": "#000"}, ) // Checking the color of the bottom border. assert-css: ( ".search-results > a", - {"border-bottom-color": "rgba(170, 170, 170, 0.2)"} + {"border-bottom-color": "#aaa3"} ) // Checking the color for "keyword" text. assert-css: ( "//*[@class='result-name']//*[text()='(keyword)']", - {"color": "rgb(0, 0, 0)"}, + {"color": "#000"}, ) -store-value: (entry_color, "rgb(0, 0, 0)") // color of the search entry -store-value: (hover_entry_color, "rgb(0, 0, 0)") // color of the hovered/focused search entry -store-value: (background_color, "rgba(0, 0, 0, 0)") // background color -store-value: (hover_background_color, "rgb(204, 204, 204)") // hover background color +store-value: (entry_color, "#000") // color of the search entry +store-value: (hover_entry_color, "#000") // color of the hovered/focused search entry +store-value: (background_color, "transparent") // background color +store-value: (hover_background_color, "#ccc") // hover background color call-function: ( "check-result-color", ( "keyword", // item kind - "rgb(56, 115, 173)", // color of item kind - "rgb(56, 115, 173)", // color of hovered/focused item kind + "#3873ad", // color of item kind + "#3873ad", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "struct", // item kind - "rgb(173, 55, 138)", // color of item kind - "rgb(173, 55, 138)", // color of hovered/focused item kind + "#ad378a", // color of item kind + "#ad378a", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "associatedtype", // item kind - "rgb(56, 115, 173)", // color of item kind - "rgb(56, 115, 173)", // color of hovered/focused item kind + "#3873ad", // color of item kind + "#3873ad", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "tymethod", // item kind - "rgb(173, 124, 55)", // color of item kind - "rgb(173, 124, 55)", // color of hovered/focused item kind + "#ad7c37", // color of item kind + "#ad7c37", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "method", // item kind - "rgb(173, 124, 55)", // color of item kind - "rgb(173, 124, 55)", // color of hovered/focused item kind + "#ad7c37", // color of item kind + "#ad7c37", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "structfield", // item kind - "rgb(0, 0, 0)", // color of item kind - "rgb(0, 0, 0)", // color of hovered/focused item kind + "#000", // color of item kind + "#000", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "macro", // item kind - "rgb(6, 128, 0)", // color of item kind - "rgb(6, 128, 0)", // color of hovered/focused item kind + "#068000", // color of item kind + "#068000", // color of hovered/focused item kind ), ) call-function: ( "check-result-color", ( "fn", // item kind - "rgb(173, 124, 55)", // color of item kind - "rgb(173, 124, 55)", // color of hovered/focused item kind + "#ad7c37", // color of item kind + "#ad7c37", // color of hovered/focused item kind ), ) @@ -357,7 +357,7 @@ move-cursor-to: ".search-input" focus: ".search-input" // To ensure the `<a>` container isnt focus or hover. assert-css: ( "//*[@class='result-name']/*[text()='test_docs::']/ancestor::a", - {"color": "rgb(0, 0, 0)", "background-color": "rgba(0, 0, 0, 0)"}, + {"color": "#000", "background-color": "transparent"}, ) // Check the alias. @@ -386,16 +386,16 @@ define-function: ( call-function: ("check-alias", { "theme": "ayu", - "alias": "rgb(197, 197, 197)", - "grey": "rgb(153, 153, 153)", + "alias": "#c5c5c5", + "grey": "#999", }) call-function: ("check-alias", { "theme": "dark", - "alias": "rgb(255, 255, 255)", - "grey": "rgb(204, 204, 204)", + "alias": "#fff", + "grey": "#ccc", }) call-function: ("check-alias", { "theme": "light", - "alias": "rgb(0, 0, 0)", - "grey": "rgb(153, 153, 153)", + "alias": "#000", + "grey": "#999", }) diff --git a/tests/rustdoc-gui/source-code-page.goml b/tests/rustdoc-gui/source-code-page.goml index 5c795928bdc..d5dd511b1d3 100644 --- a/tests/rustdoc-gui/source-code-page.goml +++ b/tests/rustdoc-gui/source-code-page.goml @@ -40,24 +40,24 @@ define-function: ( call-function: ("check-colors", { "theme": "ayu", - "color": "rgb(92, 103, 115)", - "background_color": "rgba(0, 0, 0, 0)", - "highlight_color": "rgb(112, 128, 144)", + "color": "#5c6773", + "background_color": "transparent", + "highlight_color": "#708090", "highlight_background_color": "rgba(255, 236, 164, 0.06)", }) call-function: ("check-colors", { "theme": "dark", - "color": "rgb(59, 145, 226)", - "background_color": "rgba(0, 0, 0, 0)", - "highlight_color": "rgb(59, 145, 226)", - "highlight_background_color": "rgb(10, 4, 47)", + "color": "#3b91e2", + "background_color": "transparent", + "highlight_color": "#3b91e2", + "highlight_background_color": "#0a042f", }) call-function: ("check-colors", { "theme": "light", - "color": "rgb(198, 126, 45)", - "background_color": "rgba(0, 0, 0, 0)", - "highlight_color": "rgb(198, 126, 45)", - "highlight_background_color": "rgb(253, 255, 211)", + "color": "#c67e2d", + "background_color": "transparent", + "highlight_color": "#c67e2d", + "highlight_background_color": "#fdffd3", }) // This is to ensure that the content is correctly align with the line numbers. diff --git a/tests/rustdoc-json/impls/impl_item_visibility.rs b/tests/rustdoc-json/impls/impl_item_visibility.rs new file mode 100644 index 00000000000..efa54d91dca --- /dev/null +++ b/tests/rustdoc-json/impls/impl_item_visibility.rs @@ -0,0 +1,26 @@ +#![feature(no_core)] +#![no_core] + +pub struct Foo; + +/// impl Foo priv +impl Foo { + fn baz() {} +} +// @!has '$.index[*][?(@.docs=="impl Foo priv")]' + + +/// impl Foo pub +impl Foo { + pub fn qux() {} +} +// @is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' + + +/// impl Foo hidden +impl Foo { + #[doc(hidden)] + pub fn __quazl(){} +} +// FIXME(#111564): Is this the right behaviour? +// @is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' diff --git a/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs b/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs new file mode 100644 index 00000000000..3c6fefc4ca2 --- /dev/null +++ b/tests/rustdoc-json/impls/impl_item_visibility_show_hidden.rs @@ -0,0 +1,28 @@ +// compile-flags: --document-hidden-items +#![feature(no_core)] +#![no_core] + +pub struct Foo; + +/// impl Foo priv +impl Foo { + fn baz() {} +} +// FIXME(#111564): Is this the right behaviour? +// @is '$.index[*][?(@.docs=="impl Foo priv")].visibility' '"default"' + + +/// impl Foo pub +impl Foo { + pub fn qux() {} +} +// @is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' + + +/// impl Foo hidden +impl Foo { + #[doc(hidden)] + pub fn __quazl(){} +} +// FIXME(#111564): Is this the right behaviour? +// @is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' diff --git a/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs b/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs new file mode 100644 index 00000000000..b98d1e4167c --- /dev/null +++ b/tests/rustdoc-json/impls/impl_item_visibility_show_private.rs @@ -0,0 +1,27 @@ +// compile-flags: --document-private-items +#![feature(no_core)] +#![no_core] + +pub struct Foo; + +/// impl Foo priv +impl Foo { + fn baz() {} +} +// @is '$.index[*][?(@.docs=="impl Foo priv")].visibility' '"default"' + + +/// impl Foo pub +impl Foo { + pub fn qux() {} +} +// @is '$.index[*][?(@.docs=="impl Foo pub")].visibility' '"default"' + + +/// impl Foo hidden +impl Foo { + #[doc(hidden)] + pub fn __quazl(){} +} +// FIXME(#111564): Is this the right behaviour? +// @is '$.index[*][?(@.docs=="impl Foo hidden")].visibility' '"default"' diff --git a/tests/rustdoc-json/type/inherent_associated_type.rs b/tests/rustdoc-json/type/inherent_associated_type.rs new file mode 100644 index 00000000000..ed63def93df --- /dev/null +++ b/tests/rustdoc-json/type/inherent_associated_type.rs @@ -0,0 +1,29 @@ +// ignore-tidy-linelength +#![feature(inherent_associated_types)] +#![feature(no_core)] +#![allow(incomplete_features)] +#![no_core] + +// @set OwnerMetadata = '$.index[*][?(@.name=="OwnerMetadata")].id' +pub struct OwnerMetadata; +// @set Owner = '$.index[*][?(@.name=="Owner")].id' +pub struct Owner; + +pub fn create() -> Owner::Metadata { + OwnerMetadata +} +// @is '$.index[*][?(@.name=="create")].inner.decl.output.kind' '"qualified_path"' +// @is '$.index[*][?(@.name=="create")].inner.decl.output.inner.name' '"Metadata"' +// @is '$.index[*][?(@.name=="create")].inner.decl.output.inner.trait' null +// @is '$.index[*][?(@.name=="create")].inner.decl.output.inner.self_type.kind' '"resolved_path"' +// @is '$.index[*][?(@.name=="create")].inner.decl.output.inner.self_type.inner.id' $Owner + +/// impl +impl Owner { + /// iat + pub type Metadata = OwnerMetadata; +} +// @set iat = '$.index[*][?(@.docs=="iat")].id' +// @is '$.index[*][?(@.docs=="impl")].inner.items[*]' $iat +// @is '$.index[*][?(@.docs=="iat")].kind' '"assoc_type"' +// @is '$.index[*][?(@.docs=="iat")].inner.default.inner.id' $OwnerMetadata diff --git a/tests/rustdoc-json/type/inherent_associated_type_bound.rs b/tests/rustdoc-json/type/inherent_associated_type_bound.rs new file mode 100644 index 00000000000..a089600b692 --- /dev/null +++ b/tests/rustdoc-json/type/inherent_associated_type_bound.rs @@ -0,0 +1,21 @@ +// ignore-tidy-linelength +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +// @set Carrier = '$.index[*][?(@.name=="Carrier")].id' +pub struct Carrier<'a>(&'a ()); + +// @is '$.index[*][?(@.name=="User")].inner.type.kind' '"function_pointer"' +// @is '$.index[*][?(@.name=="User")].inner.type.inner.generic_params[*].name' \""'b"\" +// @is '$.index[*][?(@.name=="User")].inner.type.inner.decl.inputs[0][1].kind' '"qualified_path"' +// @is '$.index[*][?(@.name=="User")].inner.type.inner.decl.inputs[0][1].inner.self_type.inner.id' $Carrier +// @is '$.index[*][?(@.name=="User")].inner.type.inner.decl.inputs[0][1].inner.self_type.inner.args.angle_bracketed.args[0].lifetime' \""'b"\" +// @is '$.index[*][?(@.name=="User")].inner.type.inner.decl.inputs[0][1].inner.name' '"Focus"' +// @is '$.index[*][?(@.name=="User")].inner.type.inner.decl.inputs[0][1].inner.trait' null +// @is '$.index[*][?(@.name=="User")].inner.type.inner.decl.inputs[0][1].inner.args.angle_bracketed.args[0].type.inner' '"i32"' + +pub type User = for<'b> fn(Carrier<'b>::Focus<i32>); + +impl<'a> Carrier<'a> { + pub type Focus<T> = &'a mut T; +} diff --git a/tests/rustdoc-json/type/inherent_associated_type_projections.rs b/tests/rustdoc-json/type/inherent_associated_type_projections.rs new file mode 100644 index 00000000000..30c68bfe56c --- /dev/null +++ b/tests/rustdoc-json/type/inherent_associated_type_projections.rs @@ -0,0 +1,33 @@ +// ignore-tidy-linelength +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +// @set Parametrized = '$.index[*][?(@.name=="Parametrized")].id' +pub struct Parametrized<T>(T); + +// @is '$.index[*][?(@.name=="Test")].inner.type.kind' '"qualified_path"' +// @is '$.index[*][?(@.name=="Test")].inner.type.inner.self_type.inner.id' $Parametrized +// @is '$.index[*][?(@.name=="Test")].inner.type.inner.self_type.inner.args.angle_bracketed.args[0].type' '{"inner": "i32", "kind": "primitive"}' +// @is '$.index[*][?(@.name=="Test")].inner.type.inner.name' '"Proj"' +// @is '$.index[*][?(@.name=="Test")].inner.type.inner.trait' null +pub type Test = Parametrized<i32>::Proj; + +/// param_bool +impl Parametrized<bool> { + /// param_bool_proj + pub type Proj = (); +} + +/// param_i32 +impl Parametrized<i32> { + /// param_i32_proj + pub type Proj = String; +} + +// @set param_bool = '$.index[*][?(@.docs=="param_bool")].id' +// @set param_i32 = '$.index[*][?(@.docs=="param_i32")].id' +// @set param_bool_proj = '$.index[*][?(@.docs=="param_bool_proj")].id' +// @set param_i32_proj = '$.index[*][?(@.docs=="param_i32_proj")].id' + +// @is '$.index[*][?(@.docs=="param_bool")].inner.items[*]' $param_bool_proj +// @is '$.index[*][?(@.docs=="param_i32")].inner.items[*]' $param_i32_proj diff --git a/tests/rustdoc/nested-items-issue-111415.rs b/tests/rustdoc/nested-items-issue-111415.rs new file mode 100644 index 00000000000..9b7688c332c --- /dev/null +++ b/tests/rustdoc/nested-items-issue-111415.rs @@ -0,0 +1,36 @@ +// Regression test for <https://github.com/rust-lang/rust/issues/111415>. +// This test ensures that only impl blocks are documented in bodies. + +#![crate_name = "foo"] + +// @has 'foo/index.html' +// Checking there are only three sections. +// @count - '//*[@id="main-content"]/*[@class="small-section-header"]' 3 +// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Structs' +// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Functions' +// @has - '//*[@id="main-content"]/*[@class="small-section-header"]' 'Traits' +// Checking that there are only three items. +// @count - '//*[@id="main-content"]//*[@class="item-name"]' 3 +// @has - '//*[@id="main-content"]//a[@href="struct.Bar.html"]' 'Bar' +// @has - '//*[@id="main-content"]//a[@href="fn.foo.html"]' 'foo' +// @has - '//*[@id="main-content"]//a[@href="trait.Foo.html"]' 'Foo' + +// Now checking that the `foo` method is visible in `Bar` page. +// @has 'foo/struct.Bar.html' +// @has - '//*[@id="method.foo"]/*[@class="code-header"]' 'pub fn foo()' +// @has - '//*[@id="method.bar"]/*[@class="code-header"]' 'fn bar()' +pub struct Bar; + +pub trait Foo { + fn bar() {} +} + +pub fn foo() { + pub mod inaccessible {} + pub fn inner() {} + pub const BAR: u32 = 0; + impl Bar { + pub fn foo() {} + } + impl Foo for Bar {} +} diff --git a/tests/rustdoc/strikethrough-in-summary.rs b/tests/rustdoc/strikethrough-in-summary.rs new file mode 100644 index 00000000000..cb6cd0e7ba6 --- /dev/null +++ b/tests/rustdoc/strikethrough-in-summary.rs @@ -0,0 +1,6 @@ +#![crate_name = "foo"] + +// @has foo/index.html '//del' 'strike' + +/// ~~strike~~ +pub fn strike() {} diff --git a/tests/ui/associated-inherent-types/inference.rs b/tests/ui/associated-inherent-types/inference.rs index 38179214fa1..ebd8e1d5594 100644 --- a/tests/ui/associated-inherent-types/inference.rs +++ b/tests/ui/associated-inherent-types/inference.rs @@ -3,6 +3,7 @@ #![feature(inherent_associated_types)] #![allow(incomplete_features)] +#![allow(dropping_copy_types)] use std::convert::identity; diff --git a/tests/ui/associated-types/associated-types-eq-3.stderr b/tests/ui/associated-types/associated-types-eq-3.stderr index 15ce4fc91cb..c3377eed20a 100644 --- a/tests/ui/associated-types/associated-types-eq-3.stderr +++ b/tests/ui/associated-types/associated-types-eq-3.stderr @@ -43,7 +43,7 @@ note: expected this to be `Bar` | LL | type A = usize; | ^^^^^ - = note: required for the cast from `isize` to the object type `dyn Foo<A = Bar>` + = note: required for the cast from `&isize` to `&dyn Foo<A = Bar>` error: aborting due to 3 previous errors diff --git a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr index a28a0b74e4a..fdec01b95e3 100644 --- a/tests/ui/associated-types/associated-types-overridden-binding-2.stderr +++ b/tests/ui/associated-types/associated-types-overridden-binding-2.stderr @@ -4,7 +4,7 @@ error[E0271]: expected `IntoIter<u32>` to be an iterator that yields `i32`, but LL | let _: &dyn I32Iterator<Item = u32> = &vec![42].into_iter(); | ^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` | - = note: required for the cast from `std::vec::IntoIter<u32>` to the object type `dyn Iterator<Item = u32, Item = i32>` + = note: required for the cast from `&std::vec::IntoIter<u32>` to `&dyn Iterator<Item = u32, Item = i32>` error: aborting due to previous error diff --git a/tests/ui/associated-types/issue-65774-1.stderr b/tests/ui/associated-types/issue-65774-1.stderr index 91b557555d5..9c77a25c432 100644 --- a/tests/ui/associated-types/issue-65774-1.stderr +++ b/tests/ui/associated-types/issue-65774-1.stderr @@ -25,7 +25,7 @@ LL | impl<'a, T: MyDisplay> MyDisplay for &'a mut T { } | --------- ^^^^^^^^^ ^^^^^^^^^ | | | unsatisfied trait bound introduced here - = note: required for the cast from `&mut T` to the object type `dyn MyDisplay` + = note: required for the cast from `&&mut T` to `&dyn MyDisplay` error: aborting due to 2 previous errors diff --git a/tests/ui/associated-types/issue-65774-2.stderr b/tests/ui/associated-types/issue-65774-2.stderr index c22302cdc26..ca8a727f0fe 100644 --- a/tests/ui/associated-types/issue-65774-2.stderr +++ b/tests/ui/associated-types/issue-65774-2.stderr @@ -18,7 +18,7 @@ LL | writer.my_write(valref) | ^^^^^^ the trait `MyDisplay` is not implemented for `T` | = help: the trait `MyDisplay` is implemented for `&'a mut T` - = note: required for the cast from `T` to the object type `dyn MyDisplay` + = note: required for the cast from `&mut T` to `&dyn MyDisplay` error: aborting due to 2 previous errors diff --git a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr index a6dbb071614..bbd5a822d8d 100644 --- a/tests/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/tests/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -35,7 +35,7 @@ error[E0271]: expected `[async block@$DIR/async-block-control-flow-static-semant LL | let _: &dyn Future<Output = ()> = █ | ^^^^^^ expected `()`, found `u8` | - = note: required for the cast from `[async block@$DIR/async-block-control-flow-static-semantics.rs:23:17: 25:6]` to the object type `dyn Future<Output = ()>` + = note: required for the cast from `&[async block@$DIR/async-block-control-flow-static-semantics.rs:23:17: 25:6]` to `&dyn Future<Output = ()>` error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:12:43 @@ -51,7 +51,7 @@ error[E0271]: expected `[async block@$DIR/async-block-control-flow-static-semant LL | let _: &dyn Future<Output = ()> = █ | ^^^^^^ expected `()`, found `u8` | - = note: required for the cast from `[async block@$DIR/async-block-control-flow-static-semantics.rs:14:17: 16:6]` to the object type `dyn Future<Output = ()>` + = note: required for the cast from `&[async block@$DIR/async-block-control-flow-static-semantics.rs:14:17: 16:6]` to `&dyn Future<Output = ()>` error[E0308]: mismatched types --> $DIR/async-block-control-flow-static-semantics.rs:49:44 diff --git a/tests/ui/async-await/issue-86507.drop_tracking.stderr b/tests/ui/async-await/issue-86507.drop_tracking.stderr index 5c8b7ef1b71..adb7b9bf4bf 100644 --- a/tests/ui/async-await/issue-86507.drop_tracking.stderr +++ b/tests/ui/async-await/issue-86507.drop_tracking.stderr @@ -13,7 +13,7 @@ note: captured value is not `Send` because `&` references cannot be sent unless | LL | let x = x; | ^ has type `&T` which is not `Send`, because `T` is not `Sync` - = note: required for the cast from `[async block@$DIR/issue-86507.rs:21:17: 23:18]` to the object type `dyn Future<Output = ()> + Send` + = note: required for the cast from `Pin<Box<[async block@$DIR/issue-86507.rs:21:17: 23:18]>>` to `Pin<Box<(dyn Future<Output = ()> + Send + 'async_trait)>>` help: consider further restricting this bound | LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T) diff --git a/tests/ui/async-await/issue-86507.drop_tracking_mir.stderr b/tests/ui/async-await/issue-86507.drop_tracking_mir.stderr index 5c8b7ef1b71..adb7b9bf4bf 100644 --- a/tests/ui/async-await/issue-86507.drop_tracking_mir.stderr +++ b/tests/ui/async-await/issue-86507.drop_tracking_mir.stderr @@ -13,7 +13,7 @@ note: captured value is not `Send` because `&` references cannot be sent unless | LL | let x = x; | ^ has type `&T` which is not `Send`, because `T` is not `Sync` - = note: required for the cast from `[async block@$DIR/issue-86507.rs:21:17: 23:18]` to the object type `dyn Future<Output = ()> + Send` + = note: required for the cast from `Pin<Box<[async block@$DIR/issue-86507.rs:21:17: 23:18]>>` to `Pin<Box<(dyn Future<Output = ()> + Send + 'async_trait)>>` help: consider further restricting this bound | LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T) diff --git a/tests/ui/async-await/issue-86507.no_drop_tracking.stderr b/tests/ui/async-await/issue-86507.no_drop_tracking.stderr index 5c8b7ef1b71..adb7b9bf4bf 100644 --- a/tests/ui/async-await/issue-86507.no_drop_tracking.stderr +++ b/tests/ui/async-await/issue-86507.no_drop_tracking.stderr @@ -13,7 +13,7 @@ note: captured value is not `Send` because `&` references cannot be sent unless | LL | let x = x; | ^ has type `&T` which is not `Send`, because `T` is not `Sync` - = note: required for the cast from `[async block@$DIR/issue-86507.rs:21:17: 23:18]` to the object type `dyn Future<Output = ()> + Send` + = note: required for the cast from `Pin<Box<[async block@$DIR/issue-86507.rs:21:17: 23:18]>>` to `Pin<Box<(dyn Future<Output = ()> + Send + 'async_trait)>>` help: consider further restricting this bound | LL | fn bar<'me, 'async_trait, T: Send + std::marker::Sync>(x: &'me T) diff --git a/tests/ui/async-await/multiple-lifetimes/partial-relation.rs b/tests/ui/async-await/multiple-lifetimes/partial-relation.rs index 02b105999f5..7375cb6d3a0 100644 --- a/tests/ui/async-await/multiple-lifetimes/partial-relation.rs +++ b/tests/ui/async-await/multiple-lifetimes/partial-relation.rs @@ -4,7 +4,7 @@ async fn lotsa_lifetimes<'a, 'b, 'c>(a: &'a u32, b: &'b u32, c: &'c u32) -> (&'a u32, &'b u32) where 'b: 'a { - drop((a, c)); + let _ = (a, c); (b, b) } diff --git a/tests/ui/attr-bad-crate-attr.rc b/tests/ui/attr-bad-crate-attr.rs index 89ba26dfd6f..89ba26dfd6f 100644 --- a/tests/ui/attr-bad-crate-attr.rc +++ b/tests/ui/attr-bad-crate-attr.rs diff --git a/tests/ui/attr-bad-crate-attr.stderr b/tests/ui/attr-bad-crate-attr.stderr new file mode 100644 index 00000000000..ff420eeea4a --- /dev/null +++ b/tests/ui/attr-bad-crate-attr.stderr @@ -0,0 +1,8 @@ +error: expected item after attributes + --> $DIR/attr-bad-crate-attr.rs:4:1 + | +LL | #[attr = "val"] // Unterminated + | ^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs b/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs index 0229ca37a69..60128c9419d 100644 --- a/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs +++ b/tests/ui/borrowck/borrowck-closures-slice-patterns-ok.rs @@ -1,6 +1,7 @@ // Check that closure captures for slice patterns are inferred correctly #![allow(unused_variables)] +#![allow(dropping_references)] // run-pass diff --git a/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs b/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs index dd6708582c1..78e965cc4bc 100644 --- a/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs +++ b/tests/ui/borrowck/borrowck-field-sensitivity-rpass.rs @@ -1,6 +1,7 @@ // run-pass #![allow(unused_mut)] #![allow(unused_variables)] +#![allow(dropping_copy_types)] // pretty-expanded FIXME #23616 struct A { a: isize, b: Box<isize> } diff --git a/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs b/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs index 1cf763f66fd..9acb1ec5e43 100644 --- a/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs +++ b/tests/ui/borrowck/borrowck-use-mut-borrow-rpass.rs @@ -1,6 +1,8 @@ // run-pass // pretty-expanded FIXME #23616 +#![allow(dropping_copy_types)] + struct A { a: isize, b: Box<isize> } fn field_copy_after_field_borrow() { diff --git a/tests/ui/borrowck/erase-error-in-mir-drop-tracking.rs b/tests/ui/borrowck/erase-error-in-mir-drop-tracking.rs new file mode 100644 index 00000000000..addbe5d658a --- /dev/null +++ b/tests/ui/borrowck/erase-error-in-mir-drop-tracking.rs @@ -0,0 +1,23 @@ +// compile-flags: -Zdrop-tracking-mir +// edition:2021 + +use std::future::Future; + +trait Client { + type Connecting<'a>: Future + Send + where + Self: 'a; + + fn connect(&'_ self) -> Self::Connecting<'a>; + //~^ ERROR use of undeclared lifetime name `'a` +} + +fn call_connect<C>(c: &'_ C) -> impl '_ + Future + Send +where + C: Client + Send + Sync, +{ + async move { c.connect().await } + //~^ ERROR `C` does not live long enough +} + +fn main() {} diff --git a/tests/ui/borrowck/erase-error-in-mir-drop-tracking.stderr b/tests/ui/borrowck/erase-error-in-mir-drop-tracking.stderr new file mode 100644 index 00000000000..53abe3dc952 --- /dev/null +++ b/tests/ui/borrowck/erase-error-in-mir-drop-tracking.stderr @@ -0,0 +1,24 @@ +error[E0261]: use of undeclared lifetime name `'a` + --> $DIR/erase-error-in-mir-drop-tracking.rs:11:46 + | +LL | fn connect(&'_ self) -> Self::Connecting<'a>; + | ^^ undeclared lifetime + | +help: consider introducing lifetime `'a` here + | +LL | fn connect<'a>(&'_ self) -> Self::Connecting<'a>; + | ++++ +help: consider introducing lifetime `'a` here + | +LL | trait Client<'a> { + | ++++ + +error: `C` does not live long enough + --> $DIR/erase-error-in-mir-drop-tracking.rs:19:5 + | +LL | async move { c.connect().await } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0261`. diff --git a/tests/ui/cfg/cfg-stmt-recovery.rs b/tests/ui/cfg/cfg-stmt-recovery.rs new file mode 100644 index 00000000000..2e0839d2a15 --- /dev/null +++ b/tests/ui/cfg/cfg-stmt-recovery.rs @@ -0,0 +1,13 @@ +// Verify that we do not ICE when failing to parse a statement in `cfg_eval`. + +#![feature(cfg_eval)] +#![feature(stmt_expr_attributes)] + +#[cfg_eval] +fn main() { + #[cfg_eval] + let _ = #[cfg(FALSE)] 0; + //~^ ERROR removing an expression is not supported in this position + //~| ERROR expected expression, found `;` + //~| ERROR removing an expression is not supported in this position +} diff --git a/tests/ui/cfg/cfg-stmt-recovery.stderr b/tests/ui/cfg/cfg-stmt-recovery.stderr new file mode 100644 index 00000000000..cb15e21fac6 --- /dev/null +++ b/tests/ui/cfg/cfg-stmt-recovery.stderr @@ -0,0 +1,20 @@ +error: removing an expression is not supported in this position + --> $DIR/cfg-stmt-recovery.rs:9:13 + | +LL | let _ = #[cfg(FALSE)] 0; + | ^^^^^^^^^^^^^ + +error: expected expression, found `;` + --> $DIR/cfg-stmt-recovery.rs:9:28 + | +LL | let _ = #[cfg(FALSE)] 0; + | ^ expected expression + +error: removing an expression is not supported in this position + --> $DIR/cfg-stmt-recovery.rs:9:13 + | +LL | let _ = #[cfg(FALSE)] 0; + | ^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/closure_context/issue-26046-fn-mut.stderr b/tests/ui/closure_context/issue-26046-fn-mut.stderr index f744b71c284..e468f6be791 100644 --- a/tests/ui/closure_context/issue-26046-fn-mut.stderr +++ b/tests/ui/closure_context/issue-26046-fn-mut.stderr @@ -9,7 +9,7 @@ LL | num += 1; LL | Box::new(closure) | ----------------- the requirement to implement `Fn` derives from here | - = note: required for the cast from `[closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21]` to the object type `dyn Fn()` + = note: required for the cast from `Box<[closure@$DIR/issue-26046-fn-mut.rs:4:19: 4:21]>` to `Box<(dyn Fn() + 'static)>` error: aborting due to previous error diff --git a/tests/ui/closure_context/issue-26046-fn-once.stderr b/tests/ui/closure_context/issue-26046-fn-once.stderr index 34f94f9dca6..41f60327ce0 100644 --- a/tests/ui/closure_context/issue-26046-fn-once.stderr +++ b/tests/ui/closure_context/issue-26046-fn-once.stderr @@ -9,7 +9,7 @@ LL | vec LL | Box::new(closure) | ----------------- the requirement to implement `Fn` derives from here | - = note: required for the cast from `[closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26]` to the object type `dyn Fn() -> Vec<u8>` + = note: required for the cast from `Box<[closure@$DIR/issue-26046-fn-once.rs:4:19: 4:26]>` to `Box<(dyn Fn() -> Vec<u8> + 'static)>` error: aborting due to previous error diff --git a/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs b/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs index ff5d284614b..98f8d5d4733 100644 --- a/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs +++ b/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.rs @@ -1,6 +1,7 @@ // run-pass #![warn(rust_2021_incompatible_closure_captures)] +#![allow(dropping_references, dropping_copy_types)] fn main() { if let a = "" { diff --git a/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.stderr b/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.stderr index 36a80e694e8..2609e2951ec 100644 --- a/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.stderr +++ b/tests/ui/closures/2229_closure_analysis/migrations/issue-78720.stderr @@ -1,5 +1,5 @@ warning: irrefutable `if let` pattern - --> $DIR/issue-78720.rs:6:8 + --> $DIR/issue-78720.rs:7:8 | LL | if let a = "" { | ^^^^^^^^^^ diff --git a/tests/ui/closures/2229_closure_analysis/optimization/edge_case_run_pass.rs b/tests/ui/closures/2229_closure_analysis/optimization/edge_case_run_pass.rs index 033fd6f1775..5496d0e5fc7 100644 --- a/tests/ui/closures/2229_closure_analysis/optimization/edge_case_run_pass.rs +++ b/tests/ui/closures/2229_closure_analysis/optimization/edge_case_run_pass.rs @@ -3,6 +3,7 @@ #![allow(unused)] #![allow(dead_code)] +#![allow(dropping_references)] struct Int(i32); struct B<'a>(&'a i32); diff --git a/tests/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs b/tests/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs index 477fdd613f5..b5e97ec1c1b 100644 --- a/tests/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs +++ b/tests/ui/closures/2229_closure_analysis/run_pass/drop_then_use_fake_reads.rs @@ -1,6 +1,8 @@ // edition:2021 // check-pass + #![feature(rustc_attrs)] +#![allow(dropping_references)] fn main() { let mut x = 1; diff --git a/tests/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr b/tests/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr index 980da536034..b976f70acf7 100644 --- a/tests/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr +++ b/tests/ui/coercion/coerce-issue-49593-box-never-windows.nofallback.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x) | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | - = note: required for the cast from `()` to the object type `dyn std::error::Error` + = note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>` error[E0277]: the trait bound `(): std::error::Error` is not satisfied --> $DIR/coerce-issue-49593-box-never-windows.rs:23:49 @@ -12,7 +12,7 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | - = note: required for the cast from `()` to the object type `(dyn std::error::Error + 'static)` + = note: required for the cast from `*mut ()` to `*mut (dyn std::error::Error + 'static)` error: aborting due to 2 previous errors diff --git a/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr b/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr index 322681b97bc..0d98fa93e5a 100644 --- a/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr +++ b/tests/ui/coercion/coerce-issue-49593-box-never.nofallback.stderr @@ -4,7 +4,7 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied LL | /* *mut $0 is coerced to Box<dyn Error> here */ Box::<_ /* ! */>::new(x) | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | - = note: required for the cast from `()` to the object type `dyn std::error::Error` + = note: required for the cast from `Box<()>` to `Box<(dyn std::error::Error + 'static)>` error[E0277]: the trait bound `(): std::error::Error` is not satisfied --> $DIR/coerce-issue-49593-box-never.rs:23:49 @@ -12,7 +12,7 @@ error[E0277]: the trait bound `(): std::error::Error` is not satisfied LL | /* *mut $0 is coerced to *mut Error here */ raw_ptr_box::<_ /* ! */>(x) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::error::Error` is not implemented for `()` | - = note: required for the cast from `()` to the object type `(dyn std::error::Error + 'static)` + = note: required for the cast from `*mut ()` to `*mut (dyn std::error::Error + 'static)` error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs index a1b711a3024..87ae83dd966 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_good.rs @@ -11,6 +11,13 @@ struct S<T> { impl<T: ConstParamTy> ConstParamTy for S<T> {} +#[derive(PartialEq, Eq, ConstParamTy)] +struct D<T> { + field: u8, + gen: T, +} + + fn check<T: ConstParamTy + ?Sized>() {} fn main() { @@ -39,5 +46,8 @@ fn main() { check::<S<u8>>(); check::<S<[&[bool]; 8]>>(); + check::<D<u8>>(); + check::<D<[&[bool]; 8]>>(); + // FIXME: test tuples } diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs index 07fd243737e..74283a37afc 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.rs @@ -10,4 +10,8 @@ struct CantParam(NotParam); impl std::marker::ConstParamTy for CantParam {} //~^ error: the trait `ConstParamTy` cannot be implemented for this type +#[derive(std::marker::ConstParamTy, Eq, PartialEq)] +//~^ error: the trait `ConstParamTy` cannot be implemented for this type +struct CantParamDerive(NotParam); + fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr index c8e065848b1..52b65d6061a 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_bad_field.stderr @@ -7,6 +7,17 @@ LL | LL | impl std::marker::ConstParamTy for CantParam {} | ^^^^^^^^^ -error: aborting due to previous error +error[E0204]: the trait `ConstParamTy` cannot be implemented for this type + --> $DIR/const_param_ty_impl_bad_field.rs:13:10 + | +LL | #[derive(std::marker::ConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | struct CantParamDerive(NotParam); + | -------- this field does not implement `ConstParamTy` + | + = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs index 17ef396164e..37986de481f 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.rs @@ -10,6 +10,10 @@ struct CantParam(ImplementsConstParamTy); impl std::marker::ConstParamTy for CantParam {} //~^ error: the type `CantParam` does not `#[derive(Eq)]` +#[derive(std::marker::ConstParamTy)] +//~^ error: the type `CantParamDerive` does not `#[derive(Eq)]` +struct CantParamDerive(ImplementsConstParamTy); + fn check<T: std::marker::ConstParamTy>() {} fn main() { diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr index ca5abf5e254..52701d55914 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_no_structural_eq.stderr @@ -7,6 +7,16 @@ LL | impl std::marker::ConstParamTy for CantParam {} note: required by a bound in `ConstParamTy` --> $SRC_DIR/core/src/marker.rs:LL:COL -error: aborting due to previous error +error[E0277]: the type `CantParamDerive` does not `#[derive(Eq)]` + --> $DIR/const_param_ty_impl_no_structural_eq.rs:13:10 + | +LL | #[derive(std::marker::ConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `StructuralEq` is not implemented for `CantParamDerive` + | +note: required by a bound in `ConstParamTy` + --> $SRC_DIR/core/src/marker.rs:LL:COL + = note: this error originates in the derive macro `std::marker::ConstParamTy` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs new file mode 100644 index 00000000000..d70377a20c1 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.rs @@ -0,0 +1,33 @@ +#![allow(incomplete_features)] +#![feature(adt_const_params, structural_match)] + +union Union { + a: u8, +} + +impl PartialEq for Union { + fn eq(&self, other: &Union) -> bool { + true + } +} +impl Eq for Union {} +impl std::marker::StructuralEq for Union {} + +impl std::marker::ConstParamTy for Union {} + +#[derive(std::marker::ConstParamTy)] +//~^ ERROR this trait cannot be derived for unions +union UnionDerive { + a: u8, +} + +impl PartialEq for UnionDerive { + fn eq(&self, other: &UnionDerive) -> bool { + true + } +} +impl Eq for UnionDerive {} +impl std::marker::StructuralEq for UnionDerive {} + + +fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr new file mode 100644 index 00000000000..29370304605 --- /dev/null +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_impl_union.stderr @@ -0,0 +1,8 @@ +error: this trait cannot be derived for unions + --> $DIR/const_param_ty_impl_union.rs:18:10 + | +LL | #[derive(std::marker::ConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/tests/ui/const-generics/defaults/trait_objects_fail.stderr b/tests/ui/const-generics/defaults/trait_objects_fail.stderr index 0e8334d0338..481d77728b9 100644 --- a/tests/ui/const-generics/defaults/trait_objects_fail.stderr +++ b/tests/ui/const-generics/defaults/trait_objects_fail.stderr @@ -5,7 +5,7 @@ LL | foo(&10_u32); | ^^^^^^^ the trait `Trait` is not implemented for `u32` | = help: the trait `Trait<2>` is implemented for `u32` - = note: required for the cast from `u32` to the object type `dyn Trait` + = note: required for the cast from `&u32` to `&dyn Trait` error[E0277]: the trait bound `bool: Traitor<_>` is not satisfied --> $DIR/trait_objects_fail.rs:28:9 @@ -14,7 +14,7 @@ LL | bar(&true); | ^^^^^ the trait `Traitor<_>` is not implemented for `bool` | = help: the trait `Traitor<2, 3>` is implemented for `bool` - = note: required for the cast from `bool` to the object type `dyn Traitor<_>` + = note: required for the cast from `&bool` to `&dyn Traitor<_>` error: aborting due to 2 previous errors diff --git a/tests/ui/consts/const-eval/format.stderr b/tests/ui/consts/const-eval/format.stderr index 70a1abb0a95..434b0744304 100644 --- a/tests/ui/consts/const-eval/format.stderr +++ b/tests/ui/consts/const-eval/format.stderr @@ -43,62 +43,6 @@ LL | println!("{:?}", 0); = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants = note: this error originates in the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) -note: erroneous constant used - --> $DIR/format.rs:2:12 - | -LL | panic!("{:?}", 0); - | ^^^^^^ - -note: erroneous constant used - --> $DIR/format.rs:2:12 - | -LL | panic!("{:?}", 0); - | ^^^^^^ - -note: erroneous constant used - --> $DIR/format.rs:2:20 - | -LL | panic!("{:?}", 0); - | ^ - | - = note: this note originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) - -note: erroneous constant used - --> $DIR/format.rs:2:20 - | -LL | panic!("{:?}", 0); - | ^ - | - = note: this note originates in the macro `$crate::const_format_args` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) - -note: erroneous constant used - --> $DIR/format.rs:8:14 - | -LL | println!("{:?}", 0); - | ^^^^^^ - -note: erroneous constant used - --> $DIR/format.rs:8:14 - | -LL | println!("{:?}", 0); - | ^^^^^^ - -note: erroneous constant used - --> $DIR/format.rs:8:22 - | -LL | println!("{:?}", 0); - | ^ - | - = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) - -note: erroneous constant used - --> $DIR/format.rs:8:22 - | -LL | println!("{:?}", 0); - | ^ - | - = note: this note originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) - error: aborting due to 5 previous errors For more information about this error, try `rustc --explain E0015`. diff --git a/tests/ui/consts/const-integer-bool-ops.rs b/tests/ui/consts/const-integer-bool-ops.rs index 4110ae3e456..35915a7a606 100644 --- a/tests/ui/consts/const-integer-bool-ops.rs +++ b/tests/ui/consts/const-integer-bool-ops.rs @@ -6,7 +6,6 @@ const X: usize = 42 && 39; //~| ERROR mismatched types //~| expected `usize`, found `bool` const ARR: [i32; X] = [99; 34]; -//~^ constant const X1: usize = 42 || 39; //~^ ERROR mismatched types @@ -16,7 +15,6 @@ const X1: usize = 42 || 39; //~| ERROR mismatched types //~| expected `usize`, found `bool` const ARR1: [i32; X1] = [99; 47]; -//~^ constant const X2: usize = -42 || -39; //~^ ERROR mismatched types @@ -26,7 +24,6 @@ const X2: usize = -42 || -39; //~| ERROR mismatched types //~| expected `usize`, found `bool` const ARR2: [i32; X2] = [99; 18446744073709551607]; -//~^ constant const X3: usize = -42 && -39; //~^ ERROR mismatched types @@ -36,43 +33,36 @@ const X3: usize = -42 && -39; //~| ERROR mismatched types //~| expected `usize`, found `bool` const ARR3: [i32; X3] = [99; 6]; -//~^ constant const Y: usize = 42.0 == 42.0; //~^ ERROR mismatched types //~| expected `usize`, found `bool` const ARRR: [i32; Y] = [99; 1]; -//~^ constant const Y1: usize = 42.0 >= 42.0; //~^ ERROR mismatched types //~| expected `usize`, found `bool` const ARRR1: [i32; Y1] = [99; 1]; -//~^ constant const Y2: usize = 42.0 <= 42.0; //~^ ERROR mismatched types //~| expected `usize`, found `bool` const ARRR2: [i32; Y2] = [99; 1]; -//~^ constant const Y3: usize = 42.0 > 42.0; //~^ ERROR mismatched types //~| expected `usize`, found `bool` const ARRR3: [i32; Y3] = [99; 0]; -//~^ constant const Y4: usize = 42.0 < 42.0; //~^ ERROR mismatched types //~| expected `usize`, found `bool` const ARRR4: [i32; Y4] = [99; 0]; -//~^ constant const Y5: usize = 42.0 != 42.0; //~^ ERROR mismatched types //~| expected `usize`, found `bool` const ARRR5: [i32; Y5] = [99; 0]; -//~^ constant fn main() { let _ = ARR; diff --git a/tests/ui/consts/const-integer-bool-ops.stderr b/tests/ui/consts/const-integer-bool-ops.stderr index b5c3b22fdbe..4e503e5a5c0 100644 --- a/tests/ui/consts/const-integer-bool-ops.stderr +++ b/tests/ui/consts/const-integer-bool-ops.stderr @@ -16,156 +16,96 @@ error[E0308]: mismatched types LL | const X: usize = 42 && 39; | ^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant used - --> $DIR/const-integer-bool-ops.rs:8:18 - | -LL | const ARR: [i32; X] = [99; 34]; - | ^ - error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:11:19 + --> $DIR/const-integer-bool-ops.rs:10:19 | LL | const X1: usize = 42 || 39; | ^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:11:25 + --> $DIR/const-integer-bool-ops.rs:10:25 | LL | const X1: usize = 42 || 39; | ^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:11:19 + --> $DIR/const-integer-bool-ops.rs:10:19 | LL | const X1: usize = 42 || 39; | ^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant used - --> $DIR/const-integer-bool-ops.rs:18:19 - | -LL | const ARR1: [i32; X1] = [99; 47]; - | ^^ - error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:21:19 + --> $DIR/const-integer-bool-ops.rs:19:19 | LL | const X2: usize = -42 || -39; | ^^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:21:26 + --> $DIR/const-integer-bool-ops.rs:19:26 | LL | const X2: usize = -42 || -39; | ^^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:21:19 + --> $DIR/const-integer-bool-ops.rs:19:19 | LL | const X2: usize = -42 || -39; | ^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant used - --> $DIR/const-integer-bool-ops.rs:28:19 - | -LL | const ARR2: [i32; X2] = [99; 18446744073709551607]; - | ^^ - error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:31:19 + --> $DIR/const-integer-bool-ops.rs:28:19 | LL | const X3: usize = -42 && -39; | ^^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:31:26 + --> $DIR/const-integer-bool-ops.rs:28:26 | LL | const X3: usize = -42 && -39; | ^^^ expected `bool`, found integer error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:31:19 + --> $DIR/const-integer-bool-ops.rs:28:19 | LL | const X3: usize = -42 && -39; | ^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant used - --> $DIR/const-integer-bool-ops.rs:38:19 - | -LL | const ARR3: [i32; X3] = [99; 6]; - | ^^ - error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:41:18 + --> $DIR/const-integer-bool-ops.rs:37:18 | LL | const Y: usize = 42.0 == 42.0; | ^^^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant used - --> $DIR/const-integer-bool-ops.rs:44:19 - | -LL | const ARRR: [i32; Y] = [99; 1]; - | ^ - error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:47:19 + --> $DIR/const-integer-bool-ops.rs:42:19 | LL | const Y1: usize = 42.0 >= 42.0; | ^^^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant used - --> $DIR/const-integer-bool-ops.rs:50:20 - | -LL | const ARRR1: [i32; Y1] = [99; 1]; - | ^^ - error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:53:19 + --> $DIR/const-integer-bool-ops.rs:47:19 | LL | const Y2: usize = 42.0 <= 42.0; | ^^^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant used - --> $DIR/const-integer-bool-ops.rs:56:20 - | -LL | const ARRR2: [i32; Y2] = [99; 1]; - | ^^ - error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:59:19 + --> $DIR/const-integer-bool-ops.rs:52:19 | LL | const Y3: usize = 42.0 > 42.0; | ^^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant used - --> $DIR/const-integer-bool-ops.rs:62:20 - | -LL | const ARRR3: [i32; Y3] = [99; 0]; - | ^^ - error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:65:19 + --> $DIR/const-integer-bool-ops.rs:57:19 | LL | const Y4: usize = 42.0 < 42.0; | ^^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant used - --> $DIR/const-integer-bool-ops.rs:68:20 - | -LL | const ARRR4: [i32; Y4] = [99; 0]; - | ^^ - error[E0308]: mismatched types - --> $DIR/const-integer-bool-ops.rs:71:19 + --> $DIR/const-integer-bool-ops.rs:62:19 | LL | const Y5: usize = 42.0 != 42.0; | ^^^^^^^^^^^^ expected `usize`, found `bool` -note: erroneous constant used - --> $DIR/const-integer-bool-ops.rs:74:20 - | -LL | const ARRR5: [i32; Y5] = [99; 0]; - | ^^ - error: aborting due to 18 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const-mut-refs/issue-76510.32bit.stderr b/tests/ui/consts/const-mut-refs/issue-76510.32bit.stderr index 109d15a8e4d..61b00be345f 100644 --- a/tests/ui/consts/const-mut-refs/issue-76510.32bit.stderr +++ b/tests/ui/consts/const-mut-refs/issue-76510.32bit.stderr @@ -19,12 +19,6 @@ error[E0596]: cannot borrow data in a `&` reference as mutable LL | const S: &'static mut str = &mut " hello "; | ^^^^^^^^^^^^^^ cannot borrow as mutable -note: erroneous constant used - --> $DIR/issue-76510.rs:11:70 - | -LL | let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3)); - | ^ - error: aborting due to 3 previous errors Some errors have detailed explanations: E0596, E0658, E0764. diff --git a/tests/ui/consts/const-mut-refs/issue-76510.64bit.stderr b/tests/ui/consts/const-mut-refs/issue-76510.64bit.stderr index 109d15a8e4d..61b00be345f 100644 --- a/tests/ui/consts/const-mut-refs/issue-76510.64bit.stderr +++ b/tests/ui/consts/const-mut-refs/issue-76510.64bit.stderr @@ -19,12 +19,6 @@ error[E0596]: cannot borrow data in a `&` reference as mutable LL | const S: &'static mut str = &mut " hello "; | ^^^^^^^^^^^^^^ cannot borrow as mutable -note: erroneous constant used - --> $DIR/issue-76510.rs:11:70 - | -LL | let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3)); - | ^ - error: aborting due to 3 previous errors Some errors have detailed explanations: E0596, E0658, E0764. diff --git a/tests/ui/consts/const-mut-refs/issue-76510.rs b/tests/ui/consts/const-mut-refs/issue-76510.rs index b853e2737f1..143d2fb6b9a 100644 --- a/tests/ui/consts/const-mut-refs/issue-76510.rs +++ b/tests/ui/consts/const-mut-refs/issue-76510.rs @@ -9,7 +9,6 @@ const S: &'static mut str = &mut " hello "; const fn trigger() -> [(); unsafe { let s = transmute::<(*const u8, usize), &ManuallyDrop<str>>((S.as_ptr(), 3)); - //~^ constant 0 }] { [(); 0] diff --git a/tests/ui/consts/const-tup-index-span.rs b/tests/ui/consts/const-tup-index-span.rs index 18f4f59d378..e77d392e694 100644 --- a/tests/ui/consts/const-tup-index-span.rs +++ b/tests/ui/consts/const-tup-index-span.rs @@ -4,7 +4,6 @@ const TUP: (usize,) = 5usize << 64; //~^ ERROR mismatched types //~| expected `(usize,)`, found `usize` const ARR: [i32; TUP.0] = []; -//~^ constant fn main() { } diff --git a/tests/ui/consts/const-tup-index-span.stderr b/tests/ui/consts/const-tup-index-span.stderr index 65f0520f8a4..d5df0df9525 100644 --- a/tests/ui/consts/const-tup-index-span.stderr +++ b/tests/ui/consts/const-tup-index-span.stderr @@ -11,12 +11,6 @@ help: use a trailing comma to create a tuple with one element LL | const TUP: (usize,) = (5usize << 64,); | + ++ -note: erroneous constant used - --> $DIR/const-tup-index-span.rs:6:18 - | -LL | const ARR: [i32; TUP.0] = []; - | ^^^ - error: aborting due to previous error For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/consts/const_forget.rs b/tests/ui/consts/const_forget.rs index ec7dde8c9ec..f06149f2cb9 100644 --- a/tests/ui/consts/const_forget.rs +++ b/tests/ui/consts/const_forget.rs @@ -1,5 +1,7 @@ // check-pass +#![allow(forgetting_copy_types)] + use std::mem::forget; const _: () = forget(0i32); diff --git a/tests/ui/consts/issue-104155.rs b/tests/ui/consts/issue-104155.rs index 1cc8f81b0d2..7b375dc0566 100644 --- a/tests/ui/consts/issue-104155.rs +++ b/tests/ui/consts/issue-104155.rs @@ -1,4 +1,7 @@ // check-pass + +#![allow(forgetting_copy_types)] + const _: () = core::mem::forget(Box::<u32>::default); const _: () = core::mem::forget(|| Box::<u32>::default()); diff --git a/tests/ui/consts/issue-54954.rs b/tests/ui/consts/issue-54954.rs index 520bf508ff3..7bcfa057019 100644 --- a/tests/ui/consts/issue-54954.rs +++ b/tests/ui/consts/issue-54954.rs @@ -9,8 +9,6 @@ trait Tt { } fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] { - //~^ constant - //~| constant z } diff --git a/tests/ui/consts/issue-54954.stderr b/tests/ui/consts/issue-54954.stderr index 85055828737..b0701bab793 100644 --- a/tests/ui/consts/issue-54954.stderr +++ b/tests/ui/consts/issue-54954.stderr @@ -16,18 +16,6 @@ LL | | core::mem::size_of::<T>() LL | | } | |_____- `Tt::const_val` defined here -note: erroneous constant used - --> $DIR/issue-54954.rs:11:15 - | -LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] { - | ^^^^^^^ - -note: erroneous constant used - --> $DIR/issue-54954.rs:11:34 - | -LL | fn f(z: [f32; ARR_LEN]) -> [f32; ARR_LEN] { - | ^^^^^^^ - error: aborting due to 2 previous errors Some errors have detailed explanations: E0379, E0790. diff --git a/tests/ui/consts/issue-56164.stderr b/tests/ui/consts/issue-56164.stderr index 003f8474463..e46c649faf0 100644 --- a/tests/ui/consts/issue-56164.stderr +++ b/tests/ui/consts/issue-56164.stderr @@ -28,18 +28,6 @@ error: function pointer calls are not allowed in constant functions LL | input() | ^^^^^^^ -note: erroneous constant used - --> $DIR/issue-56164.rs:1:18 - | -LL | const fn foo() { (||{})() } - | ^^^^^^ - -note: erroneous constant used - --> $DIR/issue-56164.rs:1:18 - | -LL | const fn foo() { (||{})() } - | ^^^^^^ - error: aborting due to 3 previous errors Some errors have detailed explanations: E0015, E0277. diff --git a/tests/ui/consts/issue-66693.stderr b/tests/ui/consts/issue-66693.stderr index e9a3fced61c..f4898fd9732 100644 --- a/tests/ui/consts/issue-66693.stderr +++ b/tests/ui/consts/issue-66693.stderr @@ -22,17 +22,5 @@ LL | panic!(&1); | = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) -note: erroneous constant used - --> $DIR/issue-66693.rs:11:12 - | -LL | panic!(&1); - | ^^ - -note: erroneous constant used - --> $DIR/issue-66693.rs:11:12 - | -LL | panic!(&1); - | ^^ - error: aborting due to 3 previous errors diff --git a/tests/ui/crate-leading-sep.rs b/tests/ui/crate-leading-sep.rs index ca5905fab41..fce97d9ba23 100644 --- a/tests/ui/crate-leading-sep.rs +++ b/tests/ui/crate-leading-sep.rs @@ -1,6 +1,8 @@ // run-pass // pretty-expanded FIXME #23616 +#![allow(dropping_copy_types)] + fn main() { use ::std::mem; mem::drop(2_usize); diff --git a/tests/ui/custom_test_frameworks/mismatch.stderr b/tests/ui/custom_test_frameworks/mismatch.stderr index 61061ae529d..31b18b2df98 100644 --- a/tests/ui/custom_test_frameworks/mismatch.stderr +++ b/tests/ui/custom_test_frameworks/mismatch.stderr @@ -6,7 +6,7 @@ LL | #[test] LL | fn wrong_kind(){} | ^^^^^^^^^^^^^^^^^ the trait `Testable` is not implemented for `TestDescAndFn` | - = note: required for the cast from `TestDescAndFn` to the object type `dyn Testable` + = note: required for the cast from `&TestDescAndFn` to `&dyn Testable` = note: this error originates in the attribute macro `test` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/tests/ui/diagnostic-width/E0271.stderr b/tests/ui/diagnostic-width/E0271.stderr index ed7b6651d01..52f415037d3 100644 --- a/tests/ui/diagnostic-width/E0271.stderr +++ b/tests/ui/diagnostic-width/E0271.stderr @@ -15,8 +15,8 @@ note: expected this to be `Foo` | LL | type Error = E; | ^ - = note: required for the cast from `Result<Result<..., ...>, ...>` to the object type `dyn Future<Error = Foo>` - = note: the full name for the casted type has been written to '$TEST_BUILD_DIR/diagnostic-width/E0271/E0271.long-type-hash.txt' + = note: required for the cast from `Box<Result<..., ...>>` to `Box<(dyn Future<Error = Foo> + 'static)>` + = note: the full name for the source type has been written to '$TEST_BUILD_DIR/diagnostic-width/E0271/E0271.long-type-hash.txt' error: aborting due to previous error diff --git a/tests/ui/drop/dropck-eyepatch-manuallydrop.rs b/tests/ui/drop/dropck-eyepatch-manuallydrop.rs new file mode 100644 index 00000000000..ff100cd941f --- /dev/null +++ b/tests/ui/drop/dropck-eyepatch-manuallydrop.rs @@ -0,0 +1,22 @@ +// check-pass +//! This test checks that dropck knows that ManuallyDrop does not drop its field. +#![feature(dropck_eyepatch)] + +use std::mem::ManuallyDrop; + +struct S<T>(ManuallyDrop<T>); + +unsafe impl<#[may_dangle] T> Drop for S<T> { + fn drop(&mut self) {} +} + +struct NonTrivialDrop<'a>(&'a str); +impl<'a> Drop for NonTrivialDrop<'a> { + fn drop(&mut self) {} +} + +fn main() { + let s = String::from("string"); + let _t = S(ManuallyDrop::new(NonTrivialDrop(&s))); + drop(s); +} diff --git a/tests/ui/drop/issue-110682.rs b/tests/ui/drop/issue-110682.rs new file mode 100644 index 00000000000..35f9c7e8d9b --- /dev/null +++ b/tests/ui/drop/issue-110682.rs @@ -0,0 +1,92 @@ +// build-pass +// compile-flags: -Zmir-opt-level=3 + +use std::fmt::Debug; +use std::mem::ManuallyDrop; +use std::ptr; + +pub trait BitRegister {} + +macro_rules! register { + ($($t:ty),+ $(,)?) => { $( + impl BitRegister for $t { + } + )* }; +} + +register!(u8, u16, u32); + +pub trait BitStore: Sized + Debug { + /// The register type that the implementor describes. + type Mem: BitRegister + Into<Self>; +} + +macro_rules! store { + ($($t:ty),+ $(,)?) => { $( + impl BitStore for $t { + type Mem = Self; + } + )+ }; +} + +store!(u8, u16, u32,); + +#[repr(C)] +pub struct BitVec<T> +where + T: BitStore, +{ + /// Region pointer describing the live portion of the owned buffer. + pointer: ptr::NonNull<T>, + /// Allocated capacity, in elements `T`, of the owned buffer. + capacity: usize, +} + +impl<T> BitVec<T> +where + T: BitStore, +{ + pub fn new() -> Self { + let pointer = ptr::NonNull::<T>::new(ptr::null_mut()).unwrap(); + + BitVec { pointer, capacity: 10 } + } + + pub fn clear(&mut self) { + unsafe { + self.set_len(0); + } + } + + #[inline] + pub unsafe fn set_len(&mut self, new_len: usize) {} + + fn with_vec<F, R>(&mut self, func: F) -> R + where + F: FnOnce(&mut ManuallyDrop<Vec<T::Mem>>) -> R, + { + let cap = self.capacity; + let elts = 10; + let mut vec = ManuallyDrop::new(unsafe { Vec::from_raw_parts(ptr::null_mut(), elts, cap) }); + let out = func(&mut vec); + + out + } +} + +impl<T> Drop for BitVec<T> +where + T: BitStore, +{ + #[inline] + fn drop(&mut self) { + // The buffer elements do not have destructors. + self.clear(); + // Run the `Vec` destructor to deällocate the buffer. + self.with_vec(|vec| unsafe { ManuallyDrop::drop(vec) }); + } +} + +fn main() { + let bitvec = BitVec::<u32>::new(); +} diff --git a/tests/ui/drop/repeat-drop.rs b/tests/ui/drop/repeat-drop.rs index 8fd46ecaf44..0afb4bb11bc 100644 --- a/tests/ui/drop/repeat-drop.rs +++ b/tests/ui/drop/repeat-drop.rs @@ -1,6 +1,8 @@ // run-pass // needs-unwind +#![allow(dropping_references, dropping_copy_types)] + static mut CHECK: usize = 0; struct DropChecker(usize); diff --git a/tests/ui/dst/dst-bad-coerce1.stderr b/tests/ui/dst/dst-bad-coerce1.stderr index ff77bd4cef8..2c75518c298 100644 --- a/tests/ui/dst/dst-bad-coerce1.stderr +++ b/tests/ui/dst/dst-bad-coerce1.stderr @@ -15,7 +15,7 @@ error[E0277]: the trait bound `Foo: Bar` is not satisfied LL | let f3: &Fat<dyn Bar> = f2; | ^^ the trait `Bar` is not implemented for `Foo` | - = note: required for the cast from `Foo` to the object type `dyn Bar` + = note: required for the cast from `&Fat<Foo>` to `&Fat<dyn Bar>` error[E0308]: mismatched types --> $DIR/dst-bad-coerce1.rs:28:27 @@ -34,7 +34,7 @@ error[E0277]: the trait bound `Foo: Bar` is not satisfied LL | let f3: &(dyn Bar,) = f2; | ^^ the trait `Bar` is not implemented for `Foo` | - = note: required for the cast from `Foo` to the object type `dyn Bar` + = note: required for the cast from `&(Foo,)` to `&(dyn Bar,)` error: aborting due to 4 previous errors diff --git a/tests/ui/dst/dst-object-from-unsized-type.stderr b/tests/ui/dst/dst-object-from-unsized-type.stderr index e24c96ebed6..d5e464aed4b 100644 --- a/tests/ui/dst/dst-object-from-unsized-type.stderr +++ b/tests/ui/dst/dst-object-from-unsized-type.stderr @@ -6,7 +6,7 @@ LL | fn test1<T: ?Sized + Foo>(t: &T) { LL | let u: &dyn Foo = t; | ^ doesn't have a size known at compile-time | - = note: required for the cast from `T` to the object type `dyn Foo` + = note: required for the cast from `&T` to `&dyn Foo` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn test1<T: ?Sized + Foo>(t: &T) { @@ -21,7 +21,7 @@ LL | fn test2<T: ?Sized + Foo>(t: &T) { LL | let v: &dyn Foo = t as &dyn Foo; | ^ doesn't have a size known at compile-time | - = note: required for the cast from `T` to the object type `dyn Foo` + = note: required for the cast from `&T` to `&dyn Foo` help: consider removing the `?Sized` bound to make the type parameter `Sized` | LL - fn test2<T: ?Sized + Foo>(t: &T) { @@ -35,7 +35,7 @@ LL | let _: &[&dyn Foo] = &["hi"]; | ^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast from `str` to the object type `dyn Foo` + = note: required for the cast from `&'static str` to `&dyn Foo` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/dst-object-from-unsized-type.rs:23:23 @@ -44,7 +44,7 @@ LL | let _: &dyn Foo = x as &dyn Foo; | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` - = note: required for the cast from `[u8]` to the object type `dyn Foo` + = note: required for the cast from `&[u8]` to `&dyn Foo` error: aborting due to 4 previous errors diff --git a/tests/ui/dupe-first-attr.rc b/tests/ui/dupe-first-attr.rs index 8b7025b7be7..d950743b41c 100644 --- a/tests/ui/dupe-first-attr.rc +++ b/tests/ui/dupe-first-attr.rs @@ -1,24 +1,26 @@ +// run-pass + // Regression test for a problem with the first mod attribute // being applied to every mod // pretty-expanded FIXME #23616 #[cfg(target_os = "linux")] -mod hello; +mod hello {} #[cfg(target_os = "macos")] -mod hello; +mod hello {} #[cfg(target_os = "windows")] -mod hello; +mod hello {} #[cfg(target_os = "freebsd")] -mod hello; +mod hello {} #[cfg(target_os = "dragonfly")] -mod hello; +mod hello {} #[cfg(target_os = "android")] -mod hello; +mod hello {} -pub fn main() { } +fn main() {} diff --git a/tests/ui/enum-discriminant/auxiliary/discr-foreign-dep.rs b/tests/ui/enum-discriminant/auxiliary/discr-foreign-dep.rs new file mode 100644 index 00000000000..a2cc10a4b22 --- /dev/null +++ b/tests/ui/enum-discriminant/auxiliary/discr-foreign-dep.rs @@ -0,0 +1,7 @@ +#[derive(Default)] +pub enum Foo { + A(u32), + #[default] + B, + C(u32), +} diff --git a/tests/ui/enum-discriminant/discr-foreign.rs b/tests/ui/enum-discriminant/discr-foreign.rs new file mode 100644 index 00000000000..e7123b34452 --- /dev/null +++ b/tests/ui/enum-discriminant/discr-foreign.rs @@ -0,0 +1,11 @@ +// aux-build:discr-foreign-dep.rs +// build-pass + +extern crate discr_foreign_dep; + +fn main() { + match Default::default() { + discr_foreign_dep::Foo::A(_) => {} + _ => {} + } +} diff --git a/tests/ui/enum-discriminant/issue-41394.rs b/tests/ui/enum-discriminant/issue-41394.rs index 07cad8796e1..06a33081340 100644 --- a/tests/ui/enum-discriminant/issue-41394.rs +++ b/tests/ui/enum-discriminant/issue-41394.rs @@ -5,7 +5,6 @@ enum Foo { enum Bar { A = Foo::A as isize - //~^ const } fn main() {} diff --git a/tests/ui/enum-discriminant/issue-41394.stderr b/tests/ui/enum-discriminant/issue-41394.stderr index 1b5c64628a1..fa95ca9c18a 100644 --- a/tests/ui/enum-discriminant/issue-41394.stderr +++ b/tests/ui/enum-discriminant/issue-41394.stderr @@ -6,12 +6,6 @@ LL | A = "" + 1 | | | &str -note: erroneous constant used - --> $DIR/issue-41394.rs:7:9 - | -LL | A = Foo::A as isize - | ^^^^^^^^^^^^^^^ - error: aborting due to previous error For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed b/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed index 47c4c9f67b6..bb093a4af4a 100644 --- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed +++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.fixed @@ -1,4 +1,7 @@ // run-rustfix + +#![allow(dropping_references)] + struct Foo { x: isize } diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs b/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs index c698de50c75..1a9f89c054f 100644 --- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs +++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.rs @@ -1,4 +1,7 @@ // run-rustfix + +#![allow(dropping_references)] + struct Foo { x: isize } diff --git a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr b/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr index 7f5106eb57e..c7067117349 100644 --- a/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr +++ b/tests/ui/explicit/explicit-call-to-supertrait-dtor.stderr @@ -1,5 +1,5 @@ error[E0040]: explicit use of destructor method - --> $DIR/explicit-call-to-supertrait-dtor.rs:19:14 + --> $DIR/explicit-call-to-supertrait-dtor.rs:22:14 | LL | self.drop(); | -----^^^^-- diff --git a/tests/ui/extenv/extenv-escaped-var.rs b/tests/ui/extenv/extenv-escaped-var.rs new file mode 100644 index 00000000000..d898feb78c6 --- /dev/null +++ b/tests/ui/extenv/extenv-escaped-var.rs @@ -0,0 +1,3 @@ +fn main() { + env!("\t"); //~ERROR environment variable `\t` not defined at compile time +} diff --git a/tests/ui/extenv/extenv-escaped-var.stderr b/tests/ui/extenv/extenv-escaped-var.stderr new file mode 100644 index 00000000000..25e218c63f3 --- /dev/null +++ b/tests/ui/extenv/extenv-escaped-var.stderr @@ -0,0 +1,11 @@ +error: environment variable `\t` not defined at compile time + --> $DIR/extenv-escaped-var.rs:2:5 + | +LL | env!("\t"); + | ^^^^^^^^^^ + | + = help: use `std::env::var("\t")` to read the variable at run time + = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error + diff --git a/tests/ui/extenv/issue-110547.stderr b/tests/ui/extenv/issue-110547.stderr index 1219630d346..10589ec2f54 100644 --- a/tests/ui/extenv/issue-110547.stderr +++ b/tests/ui/extenv/issue-110547.stderr @@ -1,28 +1,28 @@ -error: environment variable ` ` not defined at compile time +error: environment variable `\t` not defined at compile time --> $DIR/issue-110547.rs:4:5 | LL | env!{"\t"}; | ^^^^^^^^^^ | - = help: use `std::env::var(" ")` to read the variable at run time + = help: use `std::env::var("\t")` to read the variable at run time = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) -error: environment variable ` ` not defined at compile time +error: environment variable `\t` not defined at compile time --> $DIR/issue-110547.rs:5:5 | LL | env!("\t"); | ^^^^^^^^^^ | - = help: use `std::env::var(" ")` to read the variable at run time + = help: use `std::env::var("\t")` to read the variable at run time = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) -error: environment variable `` not defined at compile time +error: environment variable `\u{2069}` not defined at compile time --> $DIR/issue-110547.rs:6:5 | LL | env!("\u{2069}"); | ^^^^^^^^^^^^^^^^ | - = help: use `std::env::var("")` to read the variable at run time + = help: use `std::env::var("\u{2069}")` to read the variable at run time = note: this error originates in the macro `env` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/extern/auxiliary/invalid-utf8.txt b/tests/ui/extern/auxiliary/invalid-utf8.txt deleted file mode 100644 index dc1115b82db..00000000000 --- a/tests/ui/extern/auxiliary/invalid-utf8.txt +++ /dev/null @@ -1 +0,0 @@ -Ã( \ No newline at end of file diff --git a/tests/ui/feature-gates/auxiliary/debugger-visualizer.natvis b/tests/ui/feature-gates/auxiliary/debugger-visualizer.natvis deleted file mode 100644 index 6eb47e3d85b..00000000000 --- a/tests/ui/feature-gates/auxiliary/debugger-visualizer.natvis +++ /dev/null @@ -1,3 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010"> -</AutoVisualizer> diff --git a/tests/ui/feature-gates/feature-gate-cfg_overflow_checks.rs b/tests/ui/feature-gates/feature-gate-cfg_overflow_checks.rs new file mode 100644 index 00000000000..cb265aa7f25 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg_overflow_checks.rs @@ -0,0 +1,6 @@ +#![crate_type = "lib"] + +#[cfg(overflow_checks)] //~ ERROR `cfg(overflow_checks)` is experimental +pub fn cast(v: i64)->u32{ + todo!() +} diff --git a/tests/ui/feature-gates/feature-gate-cfg_overflow_checks.stderr b/tests/ui/feature-gates/feature-gate-cfg_overflow_checks.stderr new file mode 100644 index 00000000000..79aba7945f6 --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-cfg_overflow_checks.stderr @@ -0,0 +1,12 @@ +error[E0658]: `cfg(overflow_checks)` is experimental and subject to change + --> $DIR/feature-gate-cfg_overflow_checks.rs:3:7 + | +LL | #[cfg(overflow_checks)] + | ^^^^^^^^^^^^^^^ + | + = note: see issue #111466 <https://github.com/rust-lang/rust/issues/111466> for more information + = help: add `#![feature(cfg_overflow_checks)]` 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/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr index d81eade8e9b..303700c7ab4 100644 --- a/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr +++ b/tests/ui/feature-gates/feature-gate-dispatch-from-dyn-missing-impl.stderr @@ -31,14 +31,7 @@ LL | trait Trait { | ----- this trait cannot be made into an object... LL | fn ptr(self: Ptr<Self>); | ^^^^^^^^^ ...because method `ptr`'s `self` parameter cannot be dispatched on -note: required for `Ptr<{integer}>` to implement `CoerceUnsized<Ptr<dyn Trait>>` - --> $DIR/feature-gate-dispatch-from-dyn-missing-impl.rs:20:40 - | -LL | impl<T: Unsize<U> + ?Sized, U: ?Sized> CoerceUnsized<Ptr<U>> for Ptr<T> {} - | --------- ^^^^^^^^^^^^^^^^^^^^^ ^^^^^^ - | | - | unsatisfied trait bound introduced here - = note: required by cast to type `Ptr<dyn Trait>` + = note: required for the cast from `Ptr<{integer}>` to `Ptr<dyn Trait>` error: aborting due to 2 previous errors diff --git a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs index 0680d234403..dce94c9eab2 100644 --- a/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs +++ b/tests/ui/feature-gates/feature-gate-unsafe_pin_internals.rs @@ -13,5 +13,4 @@ fn non_unsafe_pin_new_unchecked<T>(pointer: &mut T) -> Pin<&mut T> { fn main() { let mut self_referential = PhantomPinned; let _: Pin<&mut PhantomPinned> = non_unsafe_pin_new_unchecked(&mut self_referential); - core::mem::forget(self_referential); // move and disable drop glue! } diff --git a/tests/ui/generator/drop-env.rs b/tests/ui/generator/drop-env.rs index 66dfb8c2c09..137a407931a 100644 --- a/tests/ui/generator/drop-env.rs +++ b/tests/ui/generator/drop-env.rs @@ -4,6 +4,7 @@ //[nomiropt]compile-flags: -Z mir-opt-level=0 #![feature(generators, generator_trait)] +#![allow(dropping_copy_types)] use std::ops::Generator; use std::pin::Pin; diff --git a/tests/ui/generator/drop-tracking-error-body.rs b/tests/ui/generator/drop-tracking-error-body.rs new file mode 100644 index 00000000000..f99d9ab6bf8 --- /dev/null +++ b/tests/ui/generator/drop-tracking-error-body.rs @@ -0,0 +1,18 @@ +// compile-flags: -Zdrop-tracking-mir --edition=2021 + +#![feature(generators)] + +pub async fn async_bad_body() { + match true {} //~ ERROR non-exhaustive patterns: type `bool` is non-empty +} + +pub fn generator_bad_body() { + || { + // 'non-exhaustive pattern' only seems to be reported once, so this annotation doesn't work + // keep the function around so we can make sure it doesn't ICE + match true {}; // ERROR non-exhaustive patterns: type `bool` is non-empty + yield (); + }; +} + +fn main() {} diff --git a/tests/ui/generator/drop-tracking-error-body.stderr b/tests/ui/generator/drop-tracking-error-body.stderr new file mode 100644 index 00000000000..28a6892336f --- /dev/null +++ b/tests/ui/generator/drop-tracking-error-body.stderr @@ -0,0 +1,17 @@ +error[E0004]: non-exhaustive patterns: type `bool` is non-empty + --> $DIR/drop-tracking-error-body.rs:6:11 + | +LL | match true {} + | ^^^^ + | + = note: the matched value is of type `bool` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown + | +LL ~ match true { +LL + _ => todo!(), +LL ~ } + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/generator/issue-57017.no_drop_tracking.stderr b/tests/ui/generator/issue-57017.no_drop_tracking.stderr index 06d2d23b9ef..f7b8e198cc4 100644 --- a/tests/ui/generator/issue-57017.no_drop_tracking.stderr +++ b/tests/ui/generator/issue-57017.no_drop_tracking.stderr @@ -1,5 +1,5 @@ error: generator cannot be sent between threads safely - --> $DIR/issue-57017.rs:31:25 + --> $DIR/issue-57017.rs:32:25 | LL | assert_send(g); | ^ generator is not `Send` @@ -15,7 +15,7 @@ LL | | ); | = help: the trait `Sync` is not implemented for `copy::unsync::Client` note: generator is not `Send` as this value is used across a yield - --> $DIR/issue-57017.rs:29:28 + --> $DIR/issue-57017.rs:30:28 | LL | let g = move || match drop(&$name::unsync::Client::default()) { | --------------------------------- has type `©::unsync::Client` which is not `Send` @@ -33,14 +33,14 @@ LL | | } LL | | ); | |_____- in this macro invocation note: required by a bound in `assert_send` - --> $DIR/issue-57017.rs:51:19 + --> $DIR/issue-57017.rs:52:19 | LL | fn assert_send<T: Send>(_thing: T) {} | ^^^^ required by this bound in `assert_send` = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) error: generator cannot be sent between threads safely - --> $DIR/issue-57017.rs:43:25 + --> $DIR/issue-57017.rs:44:25 | LL | assert_send(g); | ^ generator is not `Send` @@ -54,9 +54,9 @@ LL | | } LL | | ); | |_____- in this macro invocation | - = help: within `[generator@$DIR/issue-57017.rs:40:21: 40:28]`, the trait `Send` is not implemented for `copy::unsend::Client` + = help: within `[generator@$DIR/issue-57017.rs:41:21: 41:28]`, the trait `Send` is not implemented for `copy::unsend::Client` note: generator is not `Send` as this value is used across a yield - --> $DIR/issue-57017.rs:41:28 + --> $DIR/issue-57017.rs:42:28 | LL | let g = move || match drop($name::unsend::Client::default()) { | -------------------------------- has type `copy::unsend::Client` which is not `Send` @@ -74,14 +74,14 @@ LL | | } LL | | ); | |_____- in this macro invocation note: required by a bound in `assert_send` - --> $DIR/issue-57017.rs:51:19 + --> $DIR/issue-57017.rs:52:19 | LL | fn assert_send<T: Send>(_thing: T) {} | ^^^^ required by this bound in `assert_send` = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) error: generator cannot be sent between threads safely - --> $DIR/issue-57017.rs:31:25 + --> $DIR/issue-57017.rs:32:25 | LL | assert_send(g); | ^ generator is not `Send` @@ -97,7 +97,7 @@ LL | | ); | = help: the trait `Sync` is not implemented for `derived_drop::unsync::Client` note: generator is not `Send` as this value is used across a yield - --> $DIR/issue-57017.rs:29:28 + --> $DIR/issue-57017.rs:30:28 | LL | let g = move || match drop(&$name::unsync::Client::default()) { | --------------------------------- has type `&derived_drop::unsync::Client` which is not `Send` @@ -115,14 +115,14 @@ LL | | } LL | | ); | |_____- in this macro invocation note: required by a bound in `assert_send` - --> $DIR/issue-57017.rs:51:19 + --> $DIR/issue-57017.rs:52:19 | LL | fn assert_send<T: Send>(_thing: T) {} | ^^^^ required by this bound in `assert_send` = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) error: generator cannot be sent between threads safely - --> $DIR/issue-57017.rs:43:25 + --> $DIR/issue-57017.rs:44:25 | LL | assert_send(g); | ^ generator is not `Send` @@ -136,9 +136,9 @@ LL | | } LL | | ); | |_____- in this macro invocation | - = help: within `[generator@$DIR/issue-57017.rs:40:21: 40:28]`, the trait `Send` is not implemented for `derived_drop::unsend::Client` + = help: within `[generator@$DIR/issue-57017.rs:41:21: 41:28]`, the trait `Send` is not implemented for `derived_drop::unsend::Client` note: generator is not `Send` as this value is used across a yield - --> $DIR/issue-57017.rs:41:28 + --> $DIR/issue-57017.rs:42:28 | LL | let g = move || match drop($name::unsend::Client::default()) { | -------------------------------- has type `derived_drop::unsend::Client` which is not `Send` @@ -156,14 +156,14 @@ LL | | } LL | | ); | |_____- in this macro invocation note: required by a bound in `assert_send` - --> $DIR/issue-57017.rs:51:19 + --> $DIR/issue-57017.rs:52:19 | LL | fn assert_send<T: Send>(_thing: T) {} | ^^^^ required by this bound in `assert_send` = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) error: generator cannot be sent between threads safely - --> $DIR/issue-57017.rs:31:25 + --> $DIR/issue-57017.rs:32:25 | LL | assert_send(g); | ^ generator is not `Send` @@ -179,7 +179,7 @@ LL | | ); | = help: the trait `Sync` is not implemented for `significant_drop::unsync::Client` note: generator is not `Send` as this value is used across a yield - --> $DIR/issue-57017.rs:29:28 + --> $DIR/issue-57017.rs:30:28 | LL | let g = move || match drop(&$name::unsync::Client::default()) { | --------------------------------- has type `&significant_drop::unsync::Client` which is not `Send` @@ -197,14 +197,14 @@ LL | | } LL | | ); | |_____- in this macro invocation note: required by a bound in `assert_send` - --> $DIR/issue-57017.rs:51:19 + --> $DIR/issue-57017.rs:52:19 | LL | fn assert_send<T: Send>(_thing: T) {} | ^^^^ required by this bound in `assert_send` = note: this error originates in the macro `type_combinations` (in Nightly builds, run with -Z macro-backtrace for more info) error: generator cannot be sent between threads safely - --> $DIR/issue-57017.rs:43:25 + --> $DIR/issue-57017.rs:44:25 | LL | assert_send(g); | ^ generator is not `Send` @@ -218,9 +218,9 @@ LL | | } LL | | ); | |_____- in this macro invocation | - = help: within `[generator@$DIR/issue-57017.rs:40:21: 40:28]`, the trait `Send` is not implemented for `significant_drop::unsend::Client` + = help: within `[generator@$DIR/issue-57017.rs:41:21: 41:28]`, the trait `Send` is not implemented for `significant_drop::unsend::Client` note: generator is not `Send` as this value is used across a yield - --> $DIR/issue-57017.rs:41:28 + --> $DIR/issue-57017.rs:42:28 | LL | let g = move || match drop($name::unsend::Client::default()) { | -------------------------------- has type `significant_drop::unsend::Client` which is not `Send` @@ -238,7 +238,7 @@ LL | | } LL | | ); | |_____- in this macro invocation note: required by a bound in `assert_send` - --> $DIR/issue-57017.rs:51:19 + --> $DIR/issue-57017.rs:52:19 | LL | fn assert_send<T: Send>(_thing: T) {} | ^^^^ required by this bound in `assert_send` diff --git a/tests/ui/generator/issue-57017.rs b/tests/ui/generator/issue-57017.rs index 03b00ac99ad..381897c77a5 100644 --- a/tests/ui/generator/issue-57017.rs +++ b/tests/ui/generator/issue-57017.rs @@ -5,6 +5,7 @@ // [drop_tracking_mir] build-pass #![feature(generators, negative_impls)] +#![allow(dropping_references, dropping_copy_types)] macro_rules! type_combinations { ( diff --git a/tests/ui/generator/non-static-is-unpin.rs b/tests/ui/generator/non-static-is-unpin.rs index 17e23f5bcd2..a5dde3912cc 100644 --- a/tests/ui/generator/non-static-is-unpin.rs +++ b/tests/ui/generator/non-static-is-unpin.rs @@ -3,6 +3,7 @@ // run-pass #![feature(generators, generator_trait)] +#![allow(dropping_copy_types)] use std::marker::{PhantomPinned, Unpin}; diff --git a/tests/ui/generator/resume-arg-size.rs b/tests/ui/generator/resume-arg-size.rs index b93dc54f7a9..195166f975b 100644 --- a/tests/ui/generator/resume-arg-size.rs +++ b/tests/ui/generator/resume-arg-size.rs @@ -1,4 +1,5 @@ #![feature(generators)] +#![allow(dropping_copy_types)] // run-pass diff --git a/tests/ui/generic-associated-types/equality-bound.stderr b/tests/ui/generic-associated-types/equality-bound.stderr index d78f7a7fbce..b21ff30a27d 100644 --- a/tests/ui/generic-associated-types/equality-bound.stderr +++ b/tests/ui/generic-associated-types/equality-bound.stderr @@ -36,7 +36,10 @@ error[E0433]: failed to resolve: use of undeclared type `I` --> $DIR/equality-bound.rs:9:41 | LL | fn sum3<J: Iterator>(i: J) -> i32 where I::Item = i32 { - | ^ use of undeclared type `I` + | ^ + | | + | use of undeclared type `I` + | help: a type parameter with a similar name exists: `J` error: aborting due to 4 previous errors diff --git a/tests/ui/generic-associated-types/issue-76535.base.stderr b/tests/ui/generic-associated-types/issue-76535.base.stderr index 52c6e3eec60..370329b9f83 100644 --- a/tests/ui/generic-associated-types/issue-76535.base.stderr +++ b/tests/ui/generic-associated-types/issue-76535.base.stderr @@ -43,8 +43,7 @@ LL | pub trait SuperTrait { LL | type SubType<'a>: SubTrait where Self: 'a; | ^^^^^^^ ...because it contains the generic associated type `SubType` = help: consider moving `SubType` to another trait - = note: required for `Box<SuperStruct>` to implement `CoerceUnsized<Box<dyn SuperTrait<SubType = SubStruct<'_>>>>` - = note: required by cast to type `Box<dyn SuperTrait<SubType = SubStruct<'_>>>` + = note: required for the cast from `Box<SuperStruct>` to `Box<dyn SuperTrait<SubType = SubStruct<'_>>>` error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/issue-79422.base.stderr b/tests/ui/generic-associated-types/issue-79422.base.stderr index f1de77bc3c0..ad704f5e9f0 100644 --- a/tests/ui/generic-associated-types/issue-79422.base.stderr +++ b/tests/ui/generic-associated-types/issue-79422.base.stderr @@ -43,8 +43,7 @@ LL | trait MapLike<K, V> { LL | type VRefCont<'a>: RefCont<'a, V> where Self: 'a; | ^^^^^^^^ ...because it contains the generic associated type `VRefCont` = help: consider moving `VRefCont` to another trait - = note: required for `Box<BTreeMap<u8, u8>>` to implement `CoerceUnsized<Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>>` - = note: required by cast to type `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>` + = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>` error: aborting due to 3 previous errors diff --git a/tests/ui/generic-associated-types/issue-79422.extended.stderr b/tests/ui/generic-associated-types/issue-79422.extended.stderr index 04184fce921..14492266cda 100644 --- a/tests/ui/generic-associated-types/issue-79422.extended.stderr +++ b/tests/ui/generic-associated-types/issue-79422.extended.stderr @@ -27,7 +27,7 @@ LL | type VRefCont<'a> = &'a V where Self: 'a; | ^^^^^ = note: expected trait object `(dyn RefCont<'_, u8> + 'static)` found reference `&u8` - = note: required for the cast from `BTreeMap<u8, u8>` to the object type `dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>` + = note: required for the cast from `Box<BTreeMap<u8, u8>>` to `Box<dyn MapLike<u8, u8, VRefCont = (dyn RefCont<'_, u8> + 'static)>>` error: aborting due to 2 previous errors diff --git a/tests/ui/generic-associated-types/issue-88595.rs b/tests/ui/generic-associated-types/issue-88595.rs index 5a40a612972..7de906e7ef3 100644 --- a/tests/ui/generic-associated-types/issue-88595.rs +++ b/tests/ui/generic-associated-types/issue-88595.rs @@ -19,4 +19,5 @@ impl<'a> A<'a> for C { type B<'b> = impl Clone; fn a(&'a self) -> Self::B<'a> {} //~ ERROR: non-defining opaque type use in defining scope + //~^ ERROR: mismatched types } diff --git a/tests/ui/generic-associated-types/issue-88595.stderr b/tests/ui/generic-associated-types/issue-88595.stderr index 79d3479af8c..d6caed85459 100644 --- a/tests/ui/generic-associated-types/issue-88595.stderr +++ b/tests/ui/generic-associated-types/issue-88595.stderr @@ -1,16 +1,34 @@ error: non-defining opaque type use in defining scope - --> $DIR/issue-88595.rs:21:35 + --> $DIR/issue-88595.rs:21:5 | LL | fn a(&'a self) -> Self::B<'a> {} - | ^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ generic argument `'a` used twice | -note: lifetime used multiple times - --> $DIR/issue-88595.rs:18:6 +note: for this opaque type + --> $DIR/issue-88595.rs:19:18 | -LL | impl<'a> A<'a> for C { - | ^^ LL | type B<'b> = impl Clone; - | ^^ + | ^^^^^^^^^^ -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/issue-88595.rs:21:23 + | +LL | type B<'b> = impl Clone; + | ---------- the expected opaque type +LL | +LL | fn a(&'a self) -> Self::B<'a> {} + | - ^^^^^^^^^^^ expected opaque type, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | + = note: expected opaque type `<C as A<'a>>::B<'a>` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/issue-88595.rs:21:5 + | +LL | fn a(&'a self) -> Self::B<'a> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/hygiene/stdlib-prelude-from-opaque-late.rs b/tests/ui/hygiene/stdlib-prelude-from-opaque-late.rs index cf65de2bc23..721bb7281c0 100644 --- a/tests/ui/hygiene/stdlib-prelude-from-opaque-late.rs +++ b/tests/ui/hygiene/stdlib-prelude-from-opaque-late.rs @@ -1,6 +1,7 @@ // check-pass #![feature(decl_macro)] +#![allow(dropping_copy_types)] macro mac() { mod m { diff --git a/tests/ui/illegal-ufcs-drop.fixed b/tests/ui/illegal-ufcs-drop.fixed index d73b391be06..c088c82791b 100644 --- a/tests/ui/illegal-ufcs-drop.fixed +++ b/tests/ui/illegal-ufcs-drop.fixed @@ -1,4 +1,7 @@ // run-rustfix + +#![allow(dropping_references)] + struct Foo; impl Drop for Foo { diff --git a/tests/ui/illegal-ufcs-drop.rs b/tests/ui/illegal-ufcs-drop.rs index 11411f55494..1389b112188 100644 --- a/tests/ui/illegal-ufcs-drop.rs +++ b/tests/ui/illegal-ufcs-drop.rs @@ -1,4 +1,7 @@ // run-rustfix + +#![allow(dropping_references)] + struct Foo; impl Drop for Foo { diff --git a/tests/ui/illegal-ufcs-drop.stderr b/tests/ui/illegal-ufcs-drop.stderr index 91f47d5e456..7a5c0612c07 100644 --- a/tests/ui/illegal-ufcs-drop.stderr +++ b/tests/ui/illegal-ufcs-drop.stderr @@ -1,5 +1,5 @@ error[E0040]: explicit use of destructor method - --> $DIR/illegal-ufcs-drop.rs:9:5 + --> $DIR/illegal-ufcs-drop.rs:12:5 | LL | Drop::drop(&mut Foo) | ^^^^^^^^^^ diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed b/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed new file mode 100644 index 00000000000..cd4f2610d3f --- /dev/null +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.fixed @@ -0,0 +1,19 @@ +// run-rustfix + +struct S<T>(T); +struct S2; + +impl<T: Default> Default for S<T> { + //~^ ERROR: unexpected `impl` keyword + //~| HELP: remove the extra `impl` + fn default() -> Self { todo!() } +} + +impl Default for S2 { + //~^ ERROR: unexpected `impl` keyword + //~| HELP: remove the extra `impl` + fn default() -> Self { todo!() } +} + + +fn main() {} diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.rs b/tests/ui/impl-trait/extra-impl-in-trait-impl.rs new file mode 100644 index 00000000000..024b703e6f2 --- /dev/null +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.rs @@ -0,0 +1,19 @@ +// run-rustfix + +struct S<T>(T); +struct S2; + +impl<T: Default> impl Default for S<T> { + //~^ ERROR: unexpected `impl` keyword + //~| HELP: remove the extra `impl` + fn default() -> Self { todo!() } +} + +impl impl Default for S2 { + //~^ ERROR: unexpected `impl` keyword + //~| HELP: remove the extra `impl` + fn default() -> Self { todo!() } +} + + +fn main() {} diff --git a/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr new file mode 100644 index 00000000000..5aafc8b64d4 --- /dev/null +++ b/tests/ui/impl-trait/extra-impl-in-trait-impl.stderr @@ -0,0 +1,26 @@ +error: unexpected `impl` keyword + --> $DIR/extra-impl-in-trait-impl.rs:6:18 + | +LL | impl<T: Default> impl Default for S<T> { + | ^^^^^ help: remove the extra `impl` + | +note: this is parsed as an `impl Trait` type, but a trait is expected at this position + --> $DIR/extra-impl-in-trait-impl.rs:6:18 + | +LL | impl<T: Default> impl Default for S<T> { + | ^^^^^^^^^^^^ + +error: unexpected `impl` keyword + --> $DIR/extra-impl-in-trait-impl.rs:12:6 + | +LL | impl impl Default for S2 { + | ^^^^^ help: remove the extra `impl` + | +note: this is parsed as an `impl Trait` type, but a trait is expected at this position + --> $DIR/extra-impl-in-trait-impl.rs:12:6 + | +LL | impl impl Default for S2 { + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/impl-trait/in-assoc-type-unconstrained.rs b/tests/ui/impl-trait/in-assoc-type-unconstrained.rs new file mode 100644 index 00000000000..c395b4195a0 --- /dev/null +++ b/tests/ui/impl-trait/in-assoc-type-unconstrained.rs @@ -0,0 +1,27 @@ +#![feature(impl_trait_in_assoc_type)] + +mod compare_ty { + trait Trait { + type Ty: IntoIterator<Item = ()>; + } + impl Trait for () { + type Ty = Option<impl Sized>; + //~^ ERROR: unconstrained opaque type + //~| ERROR: type mismatch resolving `<Option<<() as Trait>::Ty::{opaque#0}> as IntoIterator>::Item == ()` + } +} + +mod compare_method { + trait Trait { + type Ty; + fn method() -> Self::Ty; + } + impl Trait for () { + type Ty = impl Sized; + //~^ ERROR: unconstrained opaque type + fn method() -> () {} + //~^ ERROR: method `method` has an incompatible type for trait + } +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr new file mode 100644 index 00000000000..1097cd0f452 --- /dev/null +++ b/tests/ui/impl-trait/in-assoc-type-unconstrained.stderr @@ -0,0 +1,59 @@ +error[E0271]: type mismatch resolving `<Option<<() as Trait>::Ty::{opaque#0}> as IntoIterator>::Item == ()` + --> $DIR/in-assoc-type-unconstrained.rs:8:19 + | +LL | type Ty = Option<impl Sized>; + | ^^^^^^^^^^^^^^^^^^ expected `()`, found opaque type + | + = note: expected unit type `()` + found opaque type `<() as compare_ty::Trait>::Ty::{opaque#0}` +note: required by a bound in `compare_ty::Trait::Ty` + --> $DIR/in-assoc-type-unconstrained.rs:5:31 + | +LL | type Ty: IntoIterator<Item = ()>; + | ^^^^^^^^^ required by this bound in `Trait::Ty` + +error: unconstrained opaque type + --> $DIR/in-assoc-type-unconstrained.rs:8:26 + | +LL | type Ty = Option<impl Sized>; + | ^^^^^^^^^^ + | + = note: `Ty` must be used in combination with a concrete type within the same impl + +error[E0053]: method `method` has an incompatible type for trait + --> $DIR/in-assoc-type-unconstrained.rs:22:24 + | +LL | type Ty = impl Sized; + | ---------- the expected opaque type +LL | +LL | fn method() -> () {} + | ^^ + | | + | expected opaque type, found `()` + | help: change the output type to match the trait: `<() as compare_method::Trait>::Ty` + | +note: type in trait + --> $DIR/in-assoc-type-unconstrained.rs:17:24 + | +LL | fn method() -> Self::Ty; + | ^^^^^^^^ + = note: expected signature `fn() -> <() as compare_method::Trait>::Ty` + found signature `fn()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/in-assoc-type-unconstrained.rs:22:9 + | +LL | fn method() -> () {} + | ^^^^^^^^^^^^^^^^^ + +error: unconstrained opaque type + --> $DIR/in-assoc-type-unconstrained.rs:20:19 + | +LL | type Ty = impl Sized; + | ^^^^^^^^^^ + | + = note: `Ty` must be used in combination with a concrete type within the same impl + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0053, E0271. +For more information about an error, try `rustc --explain E0053`. diff --git a/tests/ui/impl-trait/in-assoc-type.rs b/tests/ui/impl-trait/in-assoc-type.rs new file mode 100644 index 00000000000..36c54bdd6de --- /dev/null +++ b/tests/ui/impl-trait/in-assoc-type.rs @@ -0,0 +1,21 @@ +#![feature(impl_trait_in_assoc_type)] + +trait Foo<T> { + type Bar; + fn foo(&self) -> <Self as Foo<()>>::Bar + where + Self: Foo<()>; +} + +impl Foo<()> for () { + type Bar = impl std::fmt::Debug; + fn foo(&self) -> Self::Bar {} +} + +impl Foo<i32> for () { + type Bar = u32; + fn foo(&self) -> <Self as Foo<()>>::Bar {} + //~^ ERROR: mismatched types +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-assoc-type.stderr b/tests/ui/impl-trait/in-assoc-type.stderr new file mode 100644 index 00000000000..f0a272dc2d5 --- /dev/null +++ b/tests/ui/impl-trait/in-assoc-type.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/in-assoc-type.rs:17:22 + | +LL | type Bar = impl std::fmt::Debug; + | -------------------- the expected opaque type +... +LL | fn foo(&self) -> <Self as Foo<()>>::Bar {} + | --- ^^^^^^^^^^^^^^^^^^^^^^ expected opaque type, found `()` + | | + | implicitly returns `()` as its body has no tail or `return` expression + | + = note: expected opaque type `<() as Foo<()>>::Bar` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/in-assoc-type.rs:17:5 + | +LL | fn foo(&self) -> <Self as Foo<()>>::Bar {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/impl-trait/in-trait/object-safety.current.stderr b/tests/ui/impl-trait/in-trait/object-safety.current.stderr index b7f2b019a77..2c340a02319 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.current.stderr +++ b/tests/ui/impl-trait/in-trait/object-safety.current.stderr @@ -42,8 +42,7 @@ LL | trait Foo { LL | fn baz(&self) -> impl Debug; | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type = help: consider moving `baz` to another trait - = note: required for `Box<u32>` to implement `CoerceUnsized<Box<dyn Foo>>` - = note: required by cast to type `Box<dyn Foo>` + = note: required for the cast from `Box<u32>` to `Box<dyn Foo>` error: aborting due to 3 previous errors diff --git a/tests/ui/impl-trait/in-trait/object-safety.next.stderr b/tests/ui/impl-trait/in-trait/object-safety.next.stderr index b7f2b019a77..2c340a02319 100644 --- a/tests/ui/impl-trait/in-trait/object-safety.next.stderr +++ b/tests/ui/impl-trait/in-trait/object-safety.next.stderr @@ -42,8 +42,7 @@ LL | trait Foo { LL | fn baz(&self) -> impl Debug; | ^^^^^^^^^^ ...because method `baz` references an `impl Trait` type in its return type = help: consider moving `baz` to another trait - = note: required for `Box<u32>` to implement `CoerceUnsized<Box<dyn Foo>>` - = note: required by cast to type `Box<dyn Foo>` + = note: required for the cast from `Box<u32>` to `Box<dyn Foo>` error: aborting due to 3 previous errors diff --git a/tests/ui/impl-trait/issue-103181-1.stderr b/tests/ui/impl-trait/issue-103181-1.current.stderr index cd026607d52..e87a9d28ae1 100644 --- a/tests/ui/impl-trait/issue-103181-1.stderr +++ b/tests/ui/impl-trait/issue-103181-1.current.stderr @@ -1,5 +1,5 @@ error[E0046]: not all trait items implemented, missing: `Error` - --> $DIR/issue-103181-1.rs:9:5 + --> $DIR/issue-103181-1.rs:11:5 | LL | type Error; | ---------- `Error` from trait diff --git a/tests/ui/impl-trait/issue-103181-1.next.stderr b/tests/ui/impl-trait/issue-103181-1.next.stderr new file mode 100644 index 00000000000..e87a9d28ae1 --- /dev/null +++ b/tests/ui/impl-trait/issue-103181-1.next.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `Error` + --> $DIR/issue-103181-1.rs:11:5 + | +LL | type Error; + | ---------- `Error` from trait +LL | } +LL | impl HttpBody for () { + | ^^^^^^^^^^^^^^^^^^^^ missing `Error` in implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. diff --git a/tests/ui/impl-trait/issue-103181-1.rs b/tests/ui/impl-trait/issue-103181-1.rs index 197aedf9d98..5154abcd690 100644 --- a/tests/ui/impl-trait/issue-103181-1.rs +++ b/tests/ui/impl-trait/issue-103181-1.rs @@ -1,3 +1,5 @@ +// revisions: current next +//[next] compile-flags: -Ztrait-solver=next // edition:2021 mod hyper { diff --git a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr index f7aff419544..fe62a8f3288 100644 --- a/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr +++ b/tests/ui/impl-trait/recursive-type-alias-impl-trait-declaration-too-subtle.stderr @@ -43,6 +43,11 @@ LL | fn eq(&self, _other: &(Bar, i32)) -> bool { | = note: expected signature `fn(&b::Bar, &(b::Foo, i32)) -> _` found signature `fn(&b::Bar, &(b::Bar, i32)) -> _` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/recursive-type-alias-impl-trait-declaration-too-subtle.rs:24:9 + | +LL | fn eq(&self, _other: &(Bar, i32)) -> bool { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 4 previous errors diff --git a/tests/ui/imports/issue-109343.rs b/tests/ui/imports/issue-109343.rs new file mode 100644 index 00000000000..0c10259bcd7 --- /dev/null +++ b/tests/ui/imports/issue-109343.rs @@ -0,0 +1,10 @@ +#![crate_type = "lib"] + +pub mod f {} +pub use unresolved::f; +//~^ ERROR unresolved import `unresolved` + +/// [g] +pub use f as g; + +fn main() {} diff --git a/tests/ui/imports/issue-109343.stderr b/tests/ui/imports/issue-109343.stderr new file mode 100644 index 00000000000..8d9a3aee980 --- /dev/null +++ b/tests/ui/imports/issue-109343.stderr @@ -0,0 +1,11 @@ +error[E0432]: unresolved import `unresolved` + --> $DIR/issue-109343.rs:4:9 + | +LL | pub use unresolved::f; + | ^^^^^^^^^^ maybe a missing crate `unresolved`? + | + = help: consider adding `extern crate unresolved` to use the `unresolved` crate + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/invalid/foo.natvis.xml b/tests/ui/invalid/foo.natvis.xml new file mode 100644 index 00000000000..c341a403902 --- /dev/null +++ b/tests/ui/invalid/foo.natvis.xml @@ -0,0 +1 @@ +<!-- empty --> diff --git a/tests/ui/invalid/invalid-debugger-visualizer-target.rs b/tests/ui/invalid/invalid-debugger-visualizer-target.rs index f9dd20dbfed..1efb9555c24 100644 --- a/tests/ui/invalid/invalid-debugger-visualizer-target.rs +++ b/tests/ui/invalid/invalid-debugger-visualizer-target.rs @@ -1,2 +1,2 @@ -#[debugger_visualizer(natvis_file = "../foo.natvis")] //~ ERROR attribute should be applied to a module +#[debugger_visualizer(natvis_file = "./foo.natvis.xml")] //~ ERROR attribute should be applied to a module fn main() {} diff --git a/tests/ui/invalid/invalid-debugger-visualizer-target.stderr b/tests/ui/invalid/invalid-debugger-visualizer-target.stderr index 7944f751859..c8a4d681379 100644 --- a/tests/ui/invalid/invalid-debugger-visualizer-target.stderr +++ b/tests/ui/invalid/invalid-debugger-visualizer-target.stderr @@ -1,8 +1,8 @@ error: attribute should be applied to a module --> $DIR/invalid-debugger-visualizer-target.rs:1:1 | -LL | #[debugger_visualizer(natvis_file = "../foo.natvis")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[debugger_visualizer(natvis_file = "./foo.natvis.xml")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/tests/ui/issues/auxiliary/issue-3136-a.rc b/tests/ui/issues/auxiliary/issue-3136-a.rc deleted file mode 100644 index cd5fd314505..00000000000 --- a/tests/ui/issues/auxiliary/issue-3136-a.rc +++ /dev/null @@ -1,4 +0,0 @@ -#![crate_type = "lib"] - -#[path = "issue-3136-a.rs"] -pub mod issue_3136_a; diff --git a/tests/ui/issues/auxiliary/issue-3136-a.rs b/tests/ui/issues/auxiliary/issue-3136-a.rs index 9bb546ab393..22bb1c8f977 100644 --- a/tests/ui/issues/auxiliary/issue-3136-a.rs +++ b/tests/ui/issues/auxiliary/issue-3136-a.rs @@ -1,11 +1,14 @@ +#![crate_type = "lib"] + trait x { fn use_x<T>(&self); } struct y(()); impl x for y { fn use_x<T>(&self) { - struct foo { //~ ERROR quux - i: () + struct foo { + //~ ERROR quux + i: (), } fn new_foo<T>(i: ()) -> foo { foo { i: i } diff --git a/tests/ui/issues/issue-14366.stderr b/tests/ui/issues/issue-14366.stderr index 10a73b245ac..df61aabf00a 100644 --- a/tests/ui/issues/issue-14366.stderr +++ b/tests/ui/issues/issue-14366.stderr @@ -5,8 +5,8 @@ LL | let _x = "test" as &dyn (::std::any::Any); | ^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast from `str` to the object type `dyn Any` -help: consider borrowing the value, since `&str` can be coerced into `dyn Any` + = note: required for the cast from `&'static str` to `&(dyn Any + 'static)` +help: consider borrowing the value, since `&&'static str` can be coerced into `&(dyn Any + 'static)` | LL | let _x = &"test" as &dyn (::std::any::Any); | + diff --git a/tests/ui/issues/issue-22034.stderr b/tests/ui/issues/issue-22034.stderr index b32de5b24b9..9833e559cbc 100644 --- a/tests/ui/issues/issue-22034.stderr +++ b/tests/ui/issues/issue-22034.stderr @@ -6,7 +6,7 @@ LL | &mut *(ptr as *mut dyn Fn()) | = help: the trait `Fn<()>` is not implemented for `()` = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` - = note: required for the cast from `()` to the object type `dyn Fn()` + = note: required for the cast from `*mut ()` to `*mut dyn Fn()` error: aborting due to previous error diff --git a/tests/ui/issues/issue-22872.stderr b/tests/ui/issues/issue-22872.stderr index 9510197197a..63222d25c01 100644 --- a/tests/ui/issues/issue-22872.stderr +++ b/tests/ui/issues/issue-22872.stderr @@ -13,7 +13,7 @@ LL | impl<'b, P> Wrap<'b> for Wrapper<P> LL | where P: Process<'b>, LL | <P as Process<'b>>::Item: Iterator { | -------- unsatisfied trait bound introduced here - = note: required for the cast from `Wrapper<P>` to the object type `dyn for<'b> Wrap<'b>` + = note: required for the cast from `Box<Wrapper<P>>` to `Box<dyn for<'b> Wrap<'b>>` help: consider further restricting the associated type | LL | fn push_process<P>(process: P) where P: Process<'static>, <P as Process<'_>>::Item: Iterator { diff --git a/tests/ui/issues/issue-3136-b.rs b/tests/ui/issues/issue-3136-b.rs index c4ca7236e76..33d97fe7c83 100644 --- a/tests/ui/issues/issue-3136-b.rs +++ b/tests/ui/issues/issue-3136-b.rs @@ -1,5 +1,5 @@ // run-pass -// aux-build:issue-3136-a.rc +// aux-build:issue-3136-a.rs // pretty-expanded FIXME #23616 diff --git a/tests/ui/iterators/collect-into-slice.rs b/tests/ui/iterators/collect-into-slice.rs index 5a8aacb1a6d..045d40a6f71 100644 --- a/tests/ui/iterators/collect-into-slice.rs +++ b/tests/ui/iterators/collect-into-slice.rs @@ -14,4 +14,10 @@ fn main() { //~| NOTE doesn't have a size known at compile-time //~| NOTE doesn't have a size known at compile-time process_slice(&some_generated_vec); + + let some_generated_vec = (0..10).collect(); + //~^ ERROR a slice of type `&[i32]` cannot be built since we need to store the elements somewhere + //~| NOTE try explicitly collecting into a `Vec<{integer}>` + //~| NOTE required by a bound in `collect` + process_slice(some_generated_vec); } diff --git a/tests/ui/iterators/collect-into-slice.stderr b/tests/ui/iterators/collect-into-slice.stderr index 29fff8c51c6..07dc561f06a 100644 --- a/tests/ui/iterators/collect-into-slice.stderr +++ b/tests/ui/iterators/collect-into-slice.stderr @@ -28,6 +28,16 @@ LL | let some_generated_vec = (0..10).collect(); note: required by a bound in `collect` --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL -error: aborting due to 3 previous errors +error[E0277]: a slice of type `&[i32]` cannot be built since we need to store the elements somewhere + --> $DIR/collect-into-slice.rs:18:38 + | +LL | let some_generated_vec = (0..10).collect(); + | ^^^^^^^ try explicitly collecting into a `Vec<{integer}>` + | + = help: the trait `FromIterator<{integer}>` is not implemented for `&[i32]` +note: required by a bound in `collect` + --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL + +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/kindck/kindck-impl-type-params.stderr b/tests/ui/kindck/kindck-impl-type-params.stderr index efb25bf83e1..53c1940491f 100644 --- a/tests/ui/kindck/kindck-impl-type-params.stderr +++ b/tests/ui/kindck/kindck-impl-type-params.stderr @@ -11,7 +11,7 @@ LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {} | ---- ^^^^^^^^^^^ ^^^^ | | | unsatisfied trait bound introduced here - = note: required for the cast from `S<T>` to the object type `dyn Gettable<T>` + = note: required for the cast from `&S<T>` to `&dyn Gettable<T>` help: consider restricting type parameter `T` | LL | fn f<T: std::marker::Send>(val: T) { @@ -30,7 +30,7 @@ LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {} | ---- ^^^^^^^^^^^ ^^^^ | | | unsatisfied trait bound introduced here - = note: required for the cast from `S<T>` to the object type `dyn Gettable<T>` + = note: required for the cast from `&S<T>` to `&dyn Gettable<T>` help: consider restricting type parameter `T` | LL | fn f<T: std::marker::Copy>(val: T) { @@ -49,7 +49,7 @@ LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {} | ---- ^^^^^^^^^^^ ^^^^ | | | unsatisfied trait bound introduced here - = note: required for the cast from `S<T>` to the object type `dyn Gettable<T>` + = note: required for the cast from `&S<T>` to `&dyn Gettable<T>` help: consider restricting type parameter `T` | LL | fn g<T: std::marker::Send>(val: T) { @@ -68,7 +68,7 @@ LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {} | ---- ^^^^^^^^^^^ ^^^^ | | | unsatisfied trait bound introduced here - = note: required for the cast from `S<T>` to the object type `dyn Gettable<T>` + = note: required for the cast from `&S<T>` to `&dyn Gettable<T>` help: consider restricting type parameter `T` | LL | fn g<T: std::marker::Copy>(val: T) { @@ -88,7 +88,7 @@ LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {} | ---- ^^^^^^^^^^^ ^^^^ | | | unsatisfied trait bound introduced here - = note: required for the cast from `S<String>` to the object type `dyn Gettable<String>` + = note: required for the cast from `Box<S<String>>` to `Box<dyn Gettable<String>>` error[E0277]: the trait bound `Foo: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:43:37 @@ -104,7 +104,7 @@ LL | impl<T: Send + Copy + 'static> Gettable<T> for S<T> {} | ---- ^^^^^^^^^^^ ^^^^ | | | unsatisfied trait bound introduced here - = note: required for the cast from `S<Foo>` to the object type `dyn Gettable<Foo>` + = note: required for the cast from `Box<S<Foo>>` to `Box<dyn Gettable<Foo>>` help: consider annotating `Foo` with `#[derive(Copy)]` | LL + #[derive(Copy)] diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr index 8d45748a6c4..29495176556 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.curr.stderr @@ -46,8 +46,7 @@ LL | trait Foo : Copy { | --- ^^^^ ...because it requires `Self: Sized` | | | this trait cannot be made into an object... - = note: required for `&Box<{integer}>` to implement `CoerceUnsized<&dyn Foo>` - = note: required by cast to type `&dyn Foo` + = note: required for the cast from `&Box<{integer}>` to `&dyn Foo` error: aborting due to 3 previous errors diff --git a/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr index 2fbb5a98a8d..3e164ebf514 100644 --- a/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr +++ b/tests/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr @@ -32,8 +32,7 @@ LL | trait Foo : Copy { | --- ^^^^ ...because it requires `Self: Sized` | | | this trait cannot be made into an object... - = note: required for `&Box<i32>` to implement `CoerceUnsized<&dyn Foo>` - = note: required by cast to type `&dyn Foo` + = note: required for the cast from `&Box<i32>` to `&dyn Foo` error: aborting due to 2 previous errors diff --git a/tests/ui/kindck/kindck-send-unsafe.rs b/tests/ui/kindck/kindck-send-unsafe.rs index 4ef30a71fa3..eb1f2a549b1 100644 --- a/tests/ui/kindck/kindck-send-unsafe.rs +++ b/tests/ui/kindck/kindck-send-unsafe.rs @@ -1,11 +1,15 @@ extern crate core; -fn assert_send<T:Send>() { } +fn assert_send<T: Send>() {} + +fn test70() { + assert_send::<*mut isize>(); + //~^ ERROR `*mut isize` cannot be sent between threads safely +} fn test71<'a>() { assert_send::<*mut &'a isize>(); //~^ ERROR `*mut &'a isize` cannot be sent between threads safely } -fn main() { -} +fn main() {} diff --git a/tests/ui/kindck/kindck-send-unsafe.rs~rust-lang_master b/tests/ui/kindck/kindck-send-unsafe.rs~rust-lang_master deleted file mode 100644 index 3f0444ec9c8..00000000000 --- a/tests/ui/kindck/kindck-send-unsafe.rs~rust-lang_master +++ /dev/null @@ -1,12 +0,0 @@ -fn assert_send<T:Send>() { } - -// unsafe ptrs are ok unless they point at unsendable things -fn test70() { - assert_send::<*mut int>(); -} -fn test71<'a>() { - assert_send::<*mut &'a int>(); //~ ERROR does not fulfill the required lifetime -} - -fn main() { -} diff --git a/tests/ui/kindck/kindck-send-unsafe.stderr b/tests/ui/kindck/kindck-send-unsafe.stderr index ceed0053caa..f1a5054abbc 100644 --- a/tests/ui/kindck/kindck-send-unsafe.stderr +++ b/tests/ui/kindck/kindck-send-unsafe.stderr @@ -1,16 +1,29 @@ -error[E0277]: `*mut &'a isize` cannot be sent between threads safely +error[E0277]: `*mut isize` cannot be sent between threads safely --> $DIR/kindck-send-unsafe.rs:6:19 | +LL | assert_send::<*mut isize>(); + | ^^^^^^^^^^ `*mut isize` cannot be sent between threads safely + | + = help: the trait `Send` is not implemented for `*mut isize` +note: required by a bound in `assert_send` + --> $DIR/kindck-send-unsafe.rs:3:19 + | +LL | fn assert_send<T: Send>() {} + | ^^^^ required by this bound in `assert_send` + +error[E0277]: `*mut &'a isize` cannot be sent between threads safely + --> $DIR/kindck-send-unsafe.rs:11:19 + | LL | assert_send::<*mut &'a isize>(); | ^^^^^^^^^^^^^^ `*mut &'a isize` cannot be sent between threads safely | = help: the trait `Send` is not implemented for `*mut &'a isize` note: required by a bound in `assert_send` - --> $DIR/kindck-send-unsafe.rs:3:18 + --> $DIR/kindck-send-unsafe.rs:3:19 | -LL | fn assert_send<T:Send>() { } - | ^^^^ required by this bound in `assert_send` +LL | fn assert_send<T: Send>() {} + | ^^^^ required by this bound in `assert_send` -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/lint/dropping_copy_types.rs b/tests/ui/lint/dropping_copy_types.rs new file mode 100644 index 00000000000..2937320e5d8 --- /dev/null +++ b/tests/ui/lint/dropping_copy_types.rs @@ -0,0 +1,79 @@ +// check-pass + +#![warn(dropping_copy_types)] + +use std::mem::drop; +use std::vec::Vec; + +#[derive(Copy, Clone)] +struct SomeStruct; + +struct AnotherStruct { + x: u8, + y: u8, + z: Vec<u8>, +} + +impl Clone for AnotherStruct { + fn clone(&self) -> AnotherStruct { + AnotherStruct { + x: self.x, + y: self.y, + z: self.z.clone(), + } + } +} + +fn main() { + let s1 = SomeStruct {}; + let s2 = s1; + let s3 = &s1; + let mut s4 = s1; + let ref s5 = s1; + + drop(s1); //~ WARN calls to `std::mem::drop` + drop(s2); //~ WARN calls to `std::mem::drop` + drop(s3); //~ WARN calls to `std::mem::drop` + drop(s4); //~ WARN calls to `std::mem::drop` + drop(s5); //~ WARN calls to `std::mem::drop` + + let a1 = AnotherStruct { + x: 255, + y: 0, + z: vec![1, 2, 3], + }; + let a2 = &a1; + let mut a3 = a1.clone(); + let ref a4 = a1; + let a5 = a1.clone(); + + drop(a2); //~ WARN calls to `std::mem::drop` + drop(a3); + drop(a4); //~ WARN calls to `std::mem::drop` + drop(a5); +} + +#[allow(unused)] +#[allow(clippy::unit_cmp)] +fn issue9482(x: u8) { + fn println_and<T>(t: T) -> T { + println!("foo"); + t + } + + match x { + // Don't lint (copy type), we only care about side-effects + 0 => drop(println_and(12)), + // Don't lint (no copy type), we only care about side-effects + 1 => drop(println_and(String::new())), + 2 => { + // Lint, even if we only care about the side-effect, it's already in a block + drop(println_and(13)); //~ WARN calls to `std::mem::drop` + }, + // Lint, idiomatic use is only in body of `Arm` + 3 if drop(println_and(14)) == () => (), //~ WARN calls to `std::mem::drop` + // Lint, not a fn/method call + 4 => drop(2),//~ WARN calls to `std::mem::drop` + _ => (), + } +} diff --git a/tests/ui/lint/dropping_copy_types.stderr b/tests/ui/lint/dropping_copy_types.stderr new file mode 100644 index 00000000000..b6291aa5ed6 --- /dev/null +++ b/tests/ui/lint/dropping_copy_types.stderr @@ -0,0 +1,108 @@ +warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types.rs:34:5 + | +LL | drop(s1); + | ^^^^^--^ + | | + | argument has type `SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result +note: the lint level is defined here + --> $DIR/dropping_copy_types.rs:3:9 + | +LL | #![warn(dropping_copy_types)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types.rs:35:5 + | +LL | drop(s2); + | ^^^^^--^ + | | + | argument has type `SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_copy_types.rs:36:5 + | +LL | drop(s3); + | ^^^^^--^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + = note: `#[warn(dropping_references)]` on by default + +warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types.rs:37:5 + | +LL | drop(s4); + | ^^^^^--^ + | | + | argument has type `SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_copy_types.rs:38:5 + | +LL | drop(s5); + | ^^^^^--^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_copy_types.rs:50:5 + | +LL | drop(a2); + | ^^^^^--^ + | | + | argument has type `&AnotherStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_copy_types.rs:52:5 + | +LL | drop(a4); + | ^^^^^--^ + | | + | argument has type `&AnotherStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types.rs:71:13 + | +LL | drop(println_and(13)); + | ^^^^^---------------^ + | | + | argument has type `i32` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types.rs:74:14 + | +LL | 3 if drop(println_and(14)) == () => (), + | ^^^^^---------------^ + | | + | argument has type `i32` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a value that implements `Copy` does nothing + --> $DIR/dropping_copy_types.rs:76:14 + | +LL | 4 => drop(2), + | ^^^^^-^ + | | + | argument has type `i32` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: 10 warnings emitted + diff --git a/src/tools/clippy/tests/ui/drop_ref.rs b/tests/ui/lint/dropping_references.rs index 10044e65f11..0d5d484f451 100644 --- a/src/tools/clippy/tests/ui/drop_ref.rs +++ b/tests/ui/lint/dropping_references.rs @@ -1,42 +1,39 @@ -#![warn(clippy::drop_ref)] -#![allow(clippy::toplevel_ref_arg)] -#![allow(clippy::map_err_ignore)] -#![allow(clippy::unnecessary_wraps, clippy::drop_non_drop)] +// check-pass -use std::mem::drop; +#![warn(dropping_references)] struct SomeStruct; fn main() { - drop(&SomeStruct); + drop(&SomeStruct); //~ WARN calls to `std::mem::drop` let mut owned1 = SomeStruct; - drop(&owned1); - drop(&&owned1); - drop(&mut owned1); - drop(owned1); //OK + drop(&owned1); //~ WARN calls to `std::mem::drop` + drop(&&owned1); //~ WARN calls to `std::mem::drop` + drop(&mut owned1); //~ WARN calls to `std::mem::drop` + drop(owned1); let reference1 = &SomeStruct; - drop(reference1); + drop(reference1); //~ WARN calls to `std::mem::drop` let reference2 = &mut SomeStruct; - drop(reference2); + drop(reference2); //~ WARN calls to `std::mem::drop` let ref reference3 = SomeStruct; - drop(reference3); + drop(reference3); //~ WARN calls to `std::mem::drop` } #[allow(dead_code)] fn test_generic_fn_drop<T>(val: T) { - drop(&val); - drop(val); //OK + drop(&val); //~ WARN calls to `std::mem::drop` + drop(val); } #[allow(dead_code)] fn test_similarly_named_function() { fn drop<T>(_val: T) {} drop(&SomeStruct); //OK; call to unrelated function which happens to have the same name - std::mem::drop(&SomeStruct); + std::mem::drop(&SomeStruct); //~ WARN calls to `std::mem::drop` } #[derive(Copy, Clone)] @@ -77,21 +74,26 @@ fn test_owl_result_2() -> Result<u8, ()> { #[allow(clippy::unit_cmp)] fn issue10122(x: u8) { // This is a function which returns a reference and has a side-effect, which means - // that calling drop() on the function is considered an idiomatic way of achieving the side-effect - // in a match arm. + // that calling drop() on the function is considered an idiomatic way of achieving + // the side-effect in a match arm. fn println_and<T>(t: &T) -> &T { println!("foo"); t } match x { - 0 => drop(println_and(&12)), // Don't lint (copy type), we only care about side-effects - 1 => drop(println_and(&String::new())), // Don't lint (no copy type), we only care about side-effects + // Don't lint (copy type), we only care about side-effects + 0 => drop(println_and(&12)), + // Don't lint (no copy type), we only care about side-effects + 1 => drop(println_and(&String::new())), 2 => { - drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block + // Lint, even if we only care about the side-effect, it's already in a block + drop(println_and(&13)); //~ WARN calls to `std::mem::drop` }, - 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm` - 4 => drop(&2), // Lint, not a fn/method call + // Lint, idiomatic use is only in body of `Arm` + 3 if drop(println_and(&14)) == () => (), //~ WARN calls to `std::mem::drop` + // Lint, not a fn/method call + 4 => drop(&2), //~ WARN calls to `std::mem::drop` _ => (), } } diff --git a/tests/ui/lint/dropping_references.stderr b/tests/ui/lint/dropping_references.stderr new file mode 100644 index 00000000000..7e25a46216e --- /dev/null +++ b/tests/ui/lint/dropping_references.stderr @@ -0,0 +1,127 @@ +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references.rs:8:5 + | +LL | drop(&SomeStruct); + | ^^^^^-----------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result +note: the lint level is defined here + --> $DIR/dropping_references.rs:3:9 + | +LL | #![warn(dropping_references)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references.rs:11:5 + | +LL | drop(&owned1); + | ^^^^^-------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references.rs:12:5 + | +LL | drop(&&owned1); + | ^^^^^--------^ + | | + | argument has type `&&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references.rs:13:5 + | +LL | drop(&mut owned1); + | ^^^^^-----------^ + | | + | argument has type `&mut SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references.rs:17:5 + | +LL | drop(reference1); + | ^^^^^----------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references.rs:20:5 + | +LL | drop(reference2); + | ^^^^^----------^ + | | + | argument has type `&mut SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references.rs:23:5 + | +LL | drop(reference3); + | ^^^^^----------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references.rs:28:5 + | +LL | drop(&val); + | ^^^^^----^ + | | + | argument has type `&T` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references.rs:36:5 + | +LL | std::mem::drop(&SomeStruct); + | ^^^^^^^^^^^^^^^-----------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references.rs:91:13 + | +LL | drop(println_and(&13)); + | ^^^^^----------------^ + | | + | argument has type `&i32` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references.rs:94:14 + | +LL | 3 if drop(println_and(&14)) == () => (), + | ^^^^^----------------^ + | | + | argument has type `&i32` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::drop` with a reference instead of an owned value does nothing + --> $DIR/dropping_references.rs:96:14 + | +LL | 4 => drop(&2), + | ^^^^^--^ + | | + | argument has type `&i32` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: 12 warnings emitted + diff --git a/tests/ui/lint/forgetting_copy_types.rs b/tests/ui/lint/forgetting_copy_types.rs new file mode 100644 index 00000000000..224c7bcd5f6 --- /dev/null +++ b/tests/ui/lint/forgetting_copy_types.rs @@ -0,0 +1,56 @@ +// check-pass + +#![warn(forgetting_copy_types)] + +use std::mem::forget; +use std::vec::Vec; + +#[derive(Copy, Clone)] +struct SomeStruct; + +struct AnotherStruct { + x: u8, + y: u8, + z: Vec<u8>, +} + +impl Clone for AnotherStruct { + fn clone(&self) -> AnotherStruct { + AnotherStruct { + x: self.x, + y: self.y, + z: self.z.clone(), + } + } +} + +fn main() { + let s1 = SomeStruct {}; + let s2 = s1; + let s3 = &s1; + let mut s4 = s1; + let ref s5 = s1; + + forget(s1); //~ WARN calls to `std::mem::forget` + forget(s2); //~ WARN calls to `std::mem::forget` + forget(s3); //~ WARN calls to `std::mem::forget` + forget(s4); //~ WARN calls to `std::mem::forget` + forget(s5); //~ WARN calls to `std::mem::forget` + + let a1 = AnotherStruct { + x: 255, + y: 0, + z: vec![1, 2, 3], + }; + let a2 = &a1; + let mut a3 = a1.clone(); + let ref a4 = a1; + let a5 = a1.clone(); + + forget(a2); //~ WARN calls to `std::mem::forget` + let a3 = &a1; + forget(a3); //~ WARN calls to `std::mem::forget` + forget(a4); //~ WARN calls to `std::mem::forget` + let a5 = a1.clone(); + forget(a5); +} diff --git a/tests/ui/lint/forgetting_copy_types.stderr b/tests/ui/lint/forgetting_copy_types.stderr new file mode 100644 index 00000000000..36d1ef5c53e --- /dev/null +++ b/tests/ui/lint/forgetting_copy_types.stderr @@ -0,0 +1,88 @@ +warning: calls to `std::mem::forget` with a value that implements `Copy` does nothing + --> $DIR/forgetting_copy_types.rs:34:5 + | +LL | forget(s1); + | ^^^^^^^--^ + | | + | argument has type `SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result +note: the lint level is defined here + --> $DIR/forgetting_copy_types.rs:3:9 + | +LL | #![warn(forgetting_copy_types)] + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::mem::forget` with a value that implements `Copy` does nothing + --> $DIR/forgetting_copy_types.rs:35:5 + | +LL | forget(s2); + | ^^^^^^^--^ + | | + | argument has type `SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_copy_types.rs:36:5 + | +LL | forget(s3); + | ^^^^^^^--^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + = note: `#[warn(forgetting_references)]` on by default + +warning: calls to `std::mem::forget` with a value that implements `Copy` does nothing + --> $DIR/forgetting_copy_types.rs:37:5 + | +LL | forget(s4); + | ^^^^^^^--^ + | | + | argument has type `SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_copy_types.rs:38:5 + | +LL | forget(s5); + | ^^^^^^^--^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_copy_types.rs:50:5 + | +LL | forget(a2); + | ^^^^^^^--^ + | | + | argument has type `&AnotherStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_copy_types.rs:52:5 + | +LL | forget(a3); + | ^^^^^^^--^ + | | + | argument has type `&AnotherStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_copy_types.rs:53:5 + | +LL | forget(a4); + | ^^^^^^^--^ + | | + | argument has type `&AnotherStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: 8 warnings emitted + diff --git a/tests/ui/lint/forgetting_references.rs b/tests/ui/lint/forgetting_references.rs new file mode 100644 index 00000000000..bd51e980031 --- /dev/null +++ b/tests/ui/lint/forgetting_references.rs @@ -0,0 +1,39 @@ +// check-pass + +#![warn(forgetting_references)] + +use std::mem::forget; + +struct SomeStruct; + +fn main() { + forget(&SomeStruct); //~ WARN calls to `std::mem::forget` + + let mut owned = SomeStruct; + forget(&owned); //~ WARN calls to `std::mem::forget` + forget(&&owned); //~ WARN calls to `std::mem::forget` + forget(&mut owned); //~ WARN calls to `std::mem::forget` + forget(owned); + + let reference1 = &SomeStruct; + forget(&*reference1); //~ WARN calls to `std::mem::forget` + + let reference2 = &mut SomeStruct; + forget(reference2); //~ WARN calls to `std::mem::forget` + + let ref reference3 = SomeStruct; + forget(reference3); //~ WARN calls to `std::mem::forget` +} + +#[allow(dead_code)] +fn test_generic_fn_forget<T>(val: T) { + forget(&val); //~ WARN calls to `std::mem::forget` + forget(val); +} + +#[allow(dead_code)] +fn test_similarly_named_function() { + fn forget<T>(_val: T) {} + forget(&SomeStruct); //OK; call to unrelated function which happens to have the same name + std::mem::forget(&SomeStruct); //~ WARN calls to `std::mem::forget` +} diff --git a/tests/ui/lint/forgetting_references.stderr b/tests/ui/lint/forgetting_references.stderr new file mode 100644 index 00000000000..5624b690789 --- /dev/null +++ b/tests/ui/lint/forgetting_references.stderr @@ -0,0 +1,97 @@ +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:10:5 + | +LL | forget(&SomeStruct); + | ^^^^^^^-----------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result +note: the lint level is defined here + --> $DIR/forgetting_references.rs:3:9 + | +LL | #![warn(forgetting_references)] + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:13:5 + | +LL | forget(&owned); + | ^^^^^^^------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:14:5 + | +LL | forget(&&owned); + | ^^^^^^^-------^ + | | + | argument has type `&&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:15:5 + | +LL | forget(&mut owned); + | ^^^^^^^----------^ + | | + | argument has type `&mut SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:19:5 + | +LL | forget(&*reference1); + | ^^^^^^^------------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:22:5 + | +LL | forget(reference2); + | ^^^^^^^----------^ + | | + | argument has type `&mut SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:25:5 + | +LL | forget(reference3); + | ^^^^^^^----------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:30:5 + | +LL | forget(&val); + | ^^^^^^^----^ + | | + | argument has type `&T` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: calls to `std::mem::forget` with a reference instead of an owned value does nothing + --> $DIR/forgetting_references.rs:38:5 + | +LL | std::mem::forget(&SomeStruct); + | ^^^^^^^^^^^^^^^^^-----------^ + | | + | argument has type `&SomeStruct` + | + = note: use `let _ = ...` to ignore the expression or result + +warning: 9 warnings emitted + diff --git a/tests/ui/lint/issue-111359.rs b/tests/ui/lint/issue-111359.rs new file mode 100644 index 00000000000..e390c3fc565 --- /dev/null +++ b/tests/ui/lint/issue-111359.rs @@ -0,0 +1,27 @@ +#[deny(missing_debug_implementations)] +#[deny(missing_copy_implementations)] + +mod priv_mod { + use std::convert::TryFrom; + + pub struct BarPub; + //~^ ERROR type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation + //~| ERROR type could implement `Copy`; consider adding `impl Copy` + struct BarPriv; + + impl<'a> TryFrom<BarPriv> for u8 { + type Error = (); + fn try_from(o: BarPriv) -> Result<Self, ()> { + unimplemented!() + } + } + + impl<'a> TryFrom<BarPub> for u8 { + type Error = (); + fn try_from(o: BarPub) -> Result<Self, ()> { + unimplemented!() + } + } +} + +fn main() {} diff --git a/tests/ui/lint/issue-111359.stderr b/tests/ui/lint/issue-111359.stderr new file mode 100644 index 00000000000..2296d8413d6 --- /dev/null +++ b/tests/ui/lint/issue-111359.stderr @@ -0,0 +1,26 @@ +error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation + --> $DIR/issue-111359.rs:7:5 + | +LL | pub struct BarPub; + | ^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-111359.rs:1:8 + | +LL | #[deny(missing_debug_implementations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: type could implement `Copy`; consider adding `impl Copy` + --> $DIR/issue-111359.rs:7:5 + | +LL | pub struct BarPub; + | ^^^^^^^^^^^^^^^^^^ + | +note: the lint level is defined here + --> $DIR/issue-111359.rs:2:8 + | +LL | #[deny(missing_copy_implementations)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/lint/unused/auxiliary/must-use-foreign.rs b/tests/ui/lint/unused/auxiliary/must-use-foreign.rs new file mode 100644 index 00000000000..f773f09c382 --- /dev/null +++ b/tests/ui/lint/unused/auxiliary/must-use-foreign.rs @@ -0,0 +1,12 @@ +// edition:2021 + +use std::future::Future; + +pub struct Manager; + +impl Manager { + #[must_use] + pub async fn new() -> (Self, impl Future<Output = ()>) { + (Manager, async {}) + } +} diff --git a/tests/ui/lint/unused/must-use-foreign.rs b/tests/ui/lint/unused/must-use-foreign.rs new file mode 100644 index 00000000000..21a11058562 --- /dev/null +++ b/tests/ui/lint/unused/must-use-foreign.rs @@ -0,0 +1,15 @@ +// edition:2021 +// aux-build:must-use-foreign.rs +// check-pass + +extern crate must_use_foreign; + +use must_use_foreign::Manager; + +async fn async_main() { + Manager::new().await.1.await; +} + +fn main() { + let _ = async_main(); +} diff --git a/tests/ui/lint/unused/unused-async.rs b/tests/ui/lint/unused/unused-async.rs index 4be93aa155a..6355f47f037 100644 --- a/tests/ui/lint/unused/unused-async.rs +++ b/tests/ui/lint/unused/unused-async.rs @@ -33,7 +33,7 @@ async fn test() { foo().await; //~ ERROR unused output of future returned by `foo` that must be used bar(); //~ ERROR unused return value of `bar` that must be used //~^ ERROR unused implementer of `Future` that must be used - bar().await; //~ ERROR unused output of future returned by `bar` that must be used + bar().await; // ok, it's not an async fn baz(); //~ ERROR unused implementer of `Future` that must be used baz().await; // ok } diff --git a/tests/ui/lint/unused/unused-async.stderr b/tests/ui/lint/unused/unused-async.stderr index 1c3702ba265..e93a40658f3 100644 --- a/tests/ui/lint/unused/unused-async.stderr +++ b/tests/ui/lint/unused/unused-async.stderr @@ -52,17 +52,6 @@ help: use `let _ = ...` to ignore the resulting value LL | let _ = bar(); | +++++++ -error: unused output of future returned by `bar` that must be used - --> $DIR/unused-async.rs:36:5 - | -LL | bar().await; - | ^^^^^^^^^^^ - | -help: use `let _ = ...` to ignore the resulting value - | -LL | let _ = bar().await; - | +++++++ - error: unused implementer of `Future` that must be used --> $DIR/unused-async.rs:37:5 | @@ -71,5 +60,5 @@ LL | baz(); | = note: futures do nothing unless you `.await` or poll them -error: aborting due to 7 previous errors +error: aborting due to 6 previous errors diff --git a/tests/ui/liveness/liveness-unused.rs b/tests/ui/liveness/liveness-unused.rs index 9c7be15fcc8..ba635e6638c 100644 --- a/tests/ui/liveness/liveness-unused.rs +++ b/tests/ui/liveness/liveness-unused.rs @@ -1,7 +1,7 @@ #![warn(unused)] #![deny(unused_variables)] #![deny(unused_assignments)] -#![allow(dead_code, non_camel_case_types, trivial_numeric_casts)] +#![allow(dead_code, non_camel_case_types, trivial_numeric_casts, dropping_copy_types)] use std::ops::AddAssign; diff --git a/tests/ui/macros/builtin-prelude-no-accidents.stderr b/tests/ui/macros/builtin-prelude-no-accidents.stderr index 56af618d484..8cd9a63b808 100644 --- a/tests/ui/macros/builtin-prelude-no-accidents.stderr +++ b/tests/ui/macros/builtin-prelude-no-accidents.stderr @@ -4,18 +4,21 @@ error[E0433]: failed to resolve: use of undeclared crate or module `env` LL | env::current_dir; | ^^^ use of undeclared crate or module `env` +error[E0433]: failed to resolve: use of undeclared crate or module `vec` + --> $DIR/builtin-prelude-no-accidents.rs:7:14 + | +LL | type B = vec::Vec<u8>; + | ^^^ + | | + | use of undeclared crate or module `vec` + | help: a struct with a similar name exists (notice the capitalization): `Vec` + error[E0433]: failed to resolve: use of undeclared crate or module `panic` --> $DIR/builtin-prelude-no-accidents.rs:6:14 | LL | type A = panic::PanicInfo; | ^^^^^ use of undeclared crate or module `panic` -error[E0433]: failed to resolve: use of undeclared crate or module `vec` - --> $DIR/builtin-prelude-no-accidents.rs:7:14 - | -LL | type B = vec::Vec<u8>; - | ^^^ use of undeclared crate or module `vec` - error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/macros/issue-111749.rs b/tests/ui/macros/issue-111749.rs new file mode 100644 index 00000000000..6c45e4e8cd7 --- /dev/null +++ b/tests/ui/macros/issue-111749.rs @@ -0,0 +1,12 @@ +macro_rules! cbor_map { + ($key:expr) => { + $key.signum(); + }; +} + +fn main() { + cbor_map! { #[test(test)] 4}; + //~^ ERROR removing an expression is not supported in this position + //~| ERROR attribute must be of the form `#[test]` + //~| WARNING this was previously accepted by the compiler but is being phased out +} diff --git a/tests/ui/macros/issue-111749.stderr b/tests/ui/macros/issue-111749.stderr new file mode 100644 index 00000000000..7db2b8e6ad1 --- /dev/null +++ b/tests/ui/macros/issue-111749.stderr @@ -0,0 +1,18 @@ +error: removing an expression is not supported in this position + --> $DIR/issue-111749.rs:8:17 + | +LL | cbor_map! { #[test(test)] 4}; + | ^^^^^^^^^^^^^ + +error: attribute must be of the form `#[test]` + --> $DIR/issue-111749.rs:8:17 + | +LL | cbor_map! { #[test(test)] 4}; + | ^^^^^^^^^^^^^ + | + = 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 #57571 <https://github.com/rust-lang/rust/issues/57571> + = note: `#[deny(ill_formed_attribute_input)]` on by default + +error: aborting due to 2 previous errors + diff --git a/tests/ui/macros/panic-temporaries-2018.rs b/tests/ui/macros/panic-temporaries-2018.rs new file mode 100644 index 00000000000..d914df38062 --- /dev/null +++ b/tests/ui/macros/panic-temporaries-2018.rs @@ -0,0 +1,55 @@ +// check-pass +// edition:2018 + +#![allow(non_fmt_panics, unreachable_code)] + +use std::fmt::{self, Display}; +use std::marker::PhantomData; + +struct NotSend { + marker: PhantomData<*const u8>, +} + +const NOT_SEND: NotSend = NotSend { marker: PhantomData }; + +impl Display for NotSend { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("this value does not implement Send") + } +} + +async fn f(_: u8) {} + +// Exercises this matcher in panic_2015: +// ($fmt:expr, $($arg:tt)+) => $crate::panicking::panic_fmt(...) +async fn panic_fmt() { + // Panic returns `!`, so the await is never reached, and in particular the + // temporaries inside the formatting machinery are not still alive at the + // await point. + let todo = "..."; + f(panic!("not yet implemented: {}", todo)).await; +} + +// Exercises ("{}", $arg:expr) => $crate::panicking::panic_display(&$arg) +async fn panic_display() { + f(panic!("{}", NOT_SEND)).await; +} + +// Exercises ($msg:expr) => $crate::panicking::panic_str($msg) +async fn panic_str() { + f(panic!((NOT_SEND, "...").1)).await; +} + +// Exercises ($msg:expr) => $crate::panicking::unreachable_display(&$msg) +async fn unreachable_display() { + f(unreachable!(NOT_SEND)).await; +} + +fn require_send(_: impl Send) {} + +fn main() { + require_send(panic_fmt()); + require_send(panic_display()); + require_send(panic_str()); + require_send(unreachable_display()); +} diff --git a/tests/ui/macros/panic-temporaries.rs b/tests/ui/macros/panic-temporaries.rs new file mode 100644 index 00000000000..db65601fb73 --- /dev/null +++ b/tests/ui/macros/panic-temporaries.rs @@ -0,0 +1,43 @@ +// check-pass +// edition:2021 + +#![allow(unreachable_code)] + +use std::fmt::{self, Display}; +use std::marker::PhantomData; + +struct NotSend { + marker: PhantomData<*const u8>, +} + +const NOT_SEND: NotSend = NotSend { marker: PhantomData }; + +impl Display for NotSend { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("this value does not implement Send") + } +} + +async fn f(_: u8) {} + +// Exercises this matcher in panic_2021: +// ($($t:tt)+) => $crate::panicking::panic_fmt(...) +async fn panic_fmt() { + // Panic returns `!`, so the await is never reached, and in particular the + // temporaries inside the formatting machinery are not still alive at the + // await point. + let todo = "..."; + f(panic!("not yet implemented: {}", todo)).await; +} + +// Exercises ("{}", $arg:expr) => $crate::panicking::panic_display(&$arg) +async fn panic_display() { + f(panic!("{}", NOT_SEND)).await; +} + +fn require_send(_: impl Send) {} + +fn main() { + require_send(panic_fmt()); + require_send(panic_display()); +} diff --git a/tests/ui/macros/parse-complex-macro-invoc-op.rs b/tests/ui/macros/parse-complex-macro-invoc-op.rs index 8fef9b0ed87..10810388d20 100644 --- a/tests/ui/macros/parse-complex-macro-invoc-op.rs +++ b/tests/ui/macros/parse-complex-macro-invoc-op.rs @@ -4,6 +4,7 @@ #![allow(unused_assignments)] #![allow(unused_variables)] #![allow(stable_features)] +#![allow(dropping_copy_types)] // Test parsing binary operators after macro invocations. diff --git a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout index ad97f7a4a75..b69b5bc3b53 100644 --- a/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout +++ b/tests/ui/macros/rfc-2011-nicer-assert-messages/non-consuming-methods-have-optimized-codegen.stdout @@ -26,7 +26,7 @@ fn arbitrary_consuming_method_for_demonstration_purposes() { { ::std::rt::panic_fmt(format_args!("Assertion failed: elem as usize\nWith captures:\n elem = {0:?}\n", - __capture0)) + __capture0)); } } }; @@ -42,7 +42,7 @@ fn addr_of() { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { ::std::rt::panic_fmt(format_args!("Assertion failed: &elem\nWith captures:\n elem = {0:?}\n", - __capture0)) + __capture0)); } } }; @@ -58,7 +58,7 @@ fn binary() { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { ::std::rt::panic_fmt(format_args!("Assertion failed: elem == 1\nWith captures:\n elem = {0:?}\n", - __capture0)) + __capture0)); } } }; @@ -71,7 +71,7 @@ fn binary() { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { ::std::rt::panic_fmt(format_args!("Assertion failed: elem >= 1\nWith captures:\n elem = {0:?}\n", - __capture0)) + __capture0)); } } }; @@ -84,7 +84,7 @@ fn binary() { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { ::std::rt::panic_fmt(format_args!("Assertion failed: elem > 0\nWith captures:\n elem = {0:?}\n", - __capture0)) + __capture0)); } } }; @@ -97,7 +97,7 @@ fn binary() { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { ::std::rt::panic_fmt(format_args!("Assertion failed: elem < 3\nWith captures:\n elem = {0:?}\n", - __capture0)) + __capture0)); } } }; @@ -110,7 +110,7 @@ fn binary() { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { ::std::rt::panic_fmt(format_args!("Assertion failed: elem <= 3\nWith captures:\n elem = {0:?}\n", - __capture0)) + __capture0)); } } }; @@ -123,7 +123,7 @@ fn binary() { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { ::std::rt::panic_fmt(format_args!("Assertion failed: elem != 3\nWith captures:\n elem = {0:?}\n", - __capture0)) + __capture0)); } } }; @@ -139,7 +139,7 @@ fn unary() { (&::core::asserting::Wrapper(__local_bind0)).try_capture(&mut __capture0); { ::std::rt::panic_fmt(format_args!("Assertion failed: *elem\nWith captures:\n elem = {0:?}\n", - __capture0)) + __capture0)); } } }; diff --git a/tests/ui/mismatched_types/cast-rfc0401.stderr b/tests/ui/mismatched_types/cast-rfc0401.stderr index 2a36a352c73..6b9ac3c5852 100644 --- a/tests/ui/mismatched_types/cast-rfc0401.stderr +++ b/tests/ui/mismatched_types/cast-rfc0401.stderr @@ -220,11 +220,7 @@ LL | let _ = fat_v as *const dyn Foo; | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` - = note: required for the cast from `[u8]` to the object type `dyn Foo` -help: consider borrowing the value, since `&[u8]` can be coerced into `dyn Foo` - | -LL | let _ = &fat_v as *const dyn Foo; - | + + = note: required for the cast from `*const [u8]` to `*const dyn Foo` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/cast-rfc0401.rs:62:13 @@ -233,11 +229,7 @@ LL | let _ = a as *const dyn Foo; | ^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast from `str` to the object type `dyn Foo` -help: consider borrowing the value, since `&str` can be coerced into `dyn Foo` - | -LL | let _ = &a as *const dyn Foo; - | + + = note: required for the cast from `*const str` to `*const dyn Foo` error[E0606]: casting `&{float}` as `f32` is invalid --> $DIR/cast-rfc0401.rs:71:30 diff --git a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr index a0f790dba15..5b6f0235123 100644 --- a/tests/ui/never_type/fallback-closure-wrap.fallback.stderr +++ b/tests/ui/never_type/fallback-closure-wrap.fallback.stderr @@ -10,7 +10,7 @@ LL | | }) as Box<dyn FnMut()>); | = note: expected unit type `()` found type `!` - = note: required for the cast from `[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]` to the object type `dyn FnMut()` + = note: required for the cast from `Box<[closure@$DIR/fallback-closure-wrap.rs:18:40: 18:47]>` to `Box<dyn FnMut()>` error: aborting due to previous error diff --git a/tests/ui/never_type/never-assign-dead-code.rs b/tests/ui/never_type/never-assign-dead-code.rs index 7bb7c87097c..39df7de5a7f 100644 --- a/tests/ui/never_type/never-assign-dead-code.rs +++ b/tests/ui/never_type/never-assign-dead-code.rs @@ -3,6 +3,7 @@ // check-pass #![feature(never_type)] +#![allow(dropping_copy_types)] #![warn(unused)] fn main() { diff --git a/tests/ui/never_type/never-assign-dead-code.stderr b/tests/ui/never_type/never-assign-dead-code.stderr index 521b82023c9..5660bde5c27 100644 --- a/tests/ui/never_type/never-assign-dead-code.stderr +++ b/tests/ui/never_type/never-assign-dead-code.stderr @@ -1,5 +1,5 @@ warning: unreachable statement - --> $DIR/never-assign-dead-code.rs:10:5 + --> $DIR/never-assign-dead-code.rs:11:5 | LL | let x: ! = panic!("aah"); | ------------- any code following this expression is unreachable @@ -7,14 +7,14 @@ LL | drop(x); | ^^^^^^^^ unreachable statement | note: the lint level is defined here - --> $DIR/never-assign-dead-code.rs:6:9 + --> $DIR/never-assign-dead-code.rs:7:9 | LL | #![warn(unused)] | ^^^^^^ = note: `#[warn(unreachable_code)]` implied by `#[warn(unused)]` warning: unreachable call - --> $DIR/never-assign-dead-code.rs:10:5 + --> $DIR/never-assign-dead-code.rs:11:5 | LL | drop(x); | ^^^^ - any code following this expression is unreachable @@ -22,7 +22,7 @@ LL | drop(x); | unreachable call warning: unused variable: `x` - --> $DIR/never-assign-dead-code.rs:9:9 + --> $DIR/never-assign-dead-code.rs:10:9 | LL | let x: ! = panic!("aah"); | ^ help: if this is intentional, prefix it with an underscore: `_x` diff --git a/tests/ui/nll/relate_tys/hr-fn-aba-as-aaa.rs b/tests/ui/nll/relate_tys/hr-fn-aba-as-aaa.rs index 7cc0acf45f2..2e9eff59386 100644 --- a/tests/ui/nll/relate_tys/hr-fn-aba-as-aaa.rs +++ b/tests/ui/nll/relate_tys/hr-fn-aba-as-aaa.rs @@ -5,6 +5,8 @@ // check-pass // compile-flags:-Zno-leak-check +#![allow(dropping_copy_types)] + fn make_it() -> for<'a, 'b> fn(&'a u32, &'b u32) -> &'a u32 { panic!() } diff --git a/tests/ui/nll/ty-outlives/projection-body.rs b/tests/ui/nll/ty-outlives/projection-body.rs index b03a539ebdb..722d6747102 100644 --- a/tests/ui/nll/ty-outlives/projection-body.rs +++ b/tests/ui/nll/ty-outlives/projection-body.rs @@ -3,6 +3,8 @@ // // check-pass +#![allow(dropping_references)] + trait MyTrait<'a> { type Output; } diff --git a/tests/ui/numbers-arithmetic/overflow-attribute-works-1.rs b/tests/ui/numbers-arithmetic/overflow-attribute-works-1.rs new file mode 100644 index 00000000000..318be2a6401 --- /dev/null +++ b/tests/ui/numbers-arithmetic/overflow-attribute-works-1.rs @@ -0,0 +1,19 @@ +// run-pass +// compile-flags: -C overflow_checks=true + +#![feature(cfg_overflow_checks)] + +fn main() { + assert!(cfg!(overflow_checks)); + assert!(compiles_differently()); +} + +#[cfg(overflow_checks)] +fn compiles_differently()->bool { + true +} + +#[cfg(not(overflow_checks))] +fn compiles_differently()->bool { + false +} diff --git a/tests/ui/numbers-arithmetic/overflow-attribute-works-2.rs b/tests/ui/numbers-arithmetic/overflow-attribute-works-2.rs new file mode 100644 index 00000000000..0367d980a64 --- /dev/null +++ b/tests/ui/numbers-arithmetic/overflow-attribute-works-2.rs @@ -0,0 +1,19 @@ +// run-pass +// compile-flags: -C overflow_checks=false + +#![feature(cfg_overflow_checks)] + +fn main() { + assert!(!cfg!(overflow_checks)); + assert!(!compiles_differently()); +} + +#[cfg(overflow_checks)] +fn compiles_differently()->bool { + true +} + +#[cfg(not(overflow_checks))] +fn compiles_differently()->bool { + false +} diff --git a/tests/ui/object-safety/issue-19538.stderr b/tests/ui/object-safety/issue-19538.stderr index 8420637b3de..183245b2322 100644 --- a/tests/ui/object-safety/issue-19538.stderr +++ b/tests/ui/object-safety/issue-19538.stderr @@ -29,8 +29,7 @@ LL | fn foo<T>(&self, val: T); LL | trait Bar: Foo { } | --- this trait cannot be made into an object... = help: consider moving `foo` to another trait - = note: required for `&mut Thing` to implement `CoerceUnsized<&mut dyn Bar>` - = note: required by cast to type `&mut dyn Bar` + = note: required for the cast from `&mut Thing` to `&mut dyn Bar` error: aborting due to 2 previous errors diff --git a/tests/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr b/tests/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr index f44de07d5da..db3e0885a85 100644 --- a/tests/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr +++ b/tests/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr @@ -12,8 +12,7 @@ LL | trait Bar { LL | const X: usize; | ^ ...because it contains this associated `const` = help: consider moving `X` to another trait - = note: required for `&T` to implement `CoerceUnsized<&dyn Bar>` - = note: required by cast to type `&dyn Bar` + = note: required for the cast from `&T` to `&dyn Bar` error: aborting due to previous error diff --git a/tests/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr b/tests/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr index 9a2d472d5e7..b200b64a1f0 100644 --- a/tests/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr +++ b/tests/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr @@ -12,8 +12,7 @@ LL | trait Bar { LL | fn bar<T>(&self, t: T); | ^^^ ...because method `bar` has generic type parameters = help: consider moving `bar` to another trait - = note: required for `&T` to implement `CoerceUnsized<&dyn Bar>` - = note: required by cast to type `&dyn Bar` + = note: required for the cast from `&T` to `&dyn Bar` error[E0038]: the trait `Bar` cannot be made into an object --> $DIR/object-safety-generics.rs:26:5 @@ -29,8 +28,7 @@ LL | trait Bar { LL | fn bar<T>(&self, t: T); | ^^^ ...because method `bar` has generic type parameters = help: consider moving `bar` to another trait - = note: required for `&T` to implement `CoerceUnsized<&dyn Bar>` - = note: required by cast to type `&dyn Bar` + = note: required for the cast from `&T` to `&dyn Bar` error: aborting due to 2 previous errors diff --git a/tests/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr b/tests/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr index 40a298bd1a7..414614d8d0b 100644 --- a/tests/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr +++ b/tests/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr @@ -12,8 +12,7 @@ LL | trait Bar { LL | fn bar(&self, x: &Self); | ^^^^^ ...because method `bar` references the `Self` type in this parameter = help: consider moving `bar` to another trait - = note: required for `&T` to implement `CoerceUnsized<&dyn Bar>` - = note: required by cast to type `&dyn Bar` + = note: required for the cast from `&T` to `&dyn Bar` error[E0038]: the trait `Baz` cannot be made into an object --> $DIR/object-safety-mentions-Self.rs:30:5 @@ -29,8 +28,7 @@ LL | trait Baz { LL | fn baz(&self) -> Self; | ^^^^ ...because method `baz` references the `Self` type in its return type = help: consider moving `baz` to another trait - = note: required for `&T` to implement `CoerceUnsized<&dyn Baz>` - = note: required by cast to type `&dyn Baz` + = note: required for the cast from `&T` to `&dyn Baz` error: aborting due to 2 previous errors diff --git a/tests/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr b/tests/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr index da87b58c9e2..befcef952a8 100644 --- a/tests/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr +++ b/tests/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr @@ -11,8 +11,7 @@ LL | trait Foo { | --- this trait cannot be made into an object... LL | fn foo() {} | ^^^ ...because associated function `foo` has no `self` parameter - = note: required for `Box<Bar>` to implement `CoerceUnsized<Box<dyn Foo>>` - = note: required by cast to type `Box<dyn Foo>` + = note: required for the cast from `Box<Bar>` to `Box<dyn Foo>` help: consider turning `foo` into a method by giving it a `&self` argument | LL | fn foo(&self) {} diff --git a/tests/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr b/tests/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr index 6c29c8d5f7c..90e5c59dd02 100644 --- a/tests/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr +++ b/tests/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr @@ -11,8 +11,7 @@ LL | trait Bar | --- this trait cannot be made into an object... LL | where Self : Sized | ^^^^^ ...because it requires `Self: Sized` - = note: required for `&T` to implement `CoerceUnsized<&dyn Bar>` - = note: required by cast to type `&dyn Bar` + = note: required for the cast from `&T` to `&dyn Bar` error: aborting due to previous error diff --git a/tests/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr b/tests/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr index 70a44ed6101..a6c22b8747e 100644 --- a/tests/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr +++ b/tests/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr @@ -11,8 +11,7 @@ LL | trait Bar : Sized { | --- ^^^^^ ...because it requires `Self: Sized` | | | this trait cannot be made into an object... - = note: required for `&T` to implement `CoerceUnsized<&dyn Bar>` - = note: required by cast to type `&dyn Bar` + = note: required for the cast from `&T` to `&dyn Bar` error: aborting due to previous error diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs index 5e66e33f8a2..31de45bc756 100644 --- a/tests/ui/offset-of/offset-of-arg-count.rs +++ b/tests/ui/offset-of/offset-of-arg-count.rs @@ -12,6 +12,11 @@ fn main() { offset_of!(S, f.,); //~ ERROR expected identifier offset_of!(S, f..); //~ ERROR no rules expected the token offset_of!(S, f..,); //~ ERROR no rules expected the token + offset_of!(Lt<'static>, bar); // issue #111657 + offset_of!(Lt<'_>, bar); // issue #111678 } struct S { f: u8, } +struct Lt<'a> { + bar: &'a (), +} diff --git a/tests/ui/offset-of/offset-of-dst-field.rs b/tests/ui/offset-of/offset-of-dst-field.rs index a0269ca2d12..3b8dc0b84a4 100644 --- a/tests/ui/offset-of/offset-of-dst-field.rs +++ b/tests/ui/offset-of/offset-of-dst-field.rs @@ -26,8 +26,24 @@ struct Gamma { z: Extern, } +struct Delta<T: ?Sized> { + x: u8, + y: u16, + z: T, +} + fn main() { offset_of!(Alpha, z); //~ ERROR the size for values of type offset_of!(Beta, z); //~ ERROR the size for values of type offset_of!(Gamma, z); //~ ERROR the size for values of type } + +fn delta() { + offset_of!(Delta<Alpha>, z); //~ ERROR the size for values of type + offset_of!(Delta<Extern>, z); //~ ERROR the size for values of type + offset_of!(Delta<dyn Trait>, z); //~ ERROR the size for values of type +} + +fn generic_with_maybe_sized<T: ?Sized>() -> usize { + offset_of!(Delta<T>, z) //~ ERROR the size for values of type +} diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr index e6e0f499236..128c783d5dd 100644 --- a/tests/ui/offset-of/offset-of-dst-field.stderr +++ b/tests/ui/offset-of/offset-of-dst-field.stderr @@ -1,5 +1,5 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/offset-of-dst-field.rs:30:5 + --> $DIR/offset-of-dst-field.rs:36:5 | LL | offset_of!(Alpha, z); | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -8,7 +8,7 @@ LL | offset_of!(Alpha, z); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time - --> $DIR/offset-of-dst-field.rs:31:5 + --> $DIR/offset-of-dst-field.rs:37:5 | LL | offset_of!(Beta, z); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -17,7 +17,7 @@ LL | offset_of!(Beta, z); = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `Extern` cannot be known at compilation time - --> $DIR/offset-of-dst-field.rs:32:5 + --> $DIR/offset-of-dst-field.rs:38:5 | LL | offset_of!(Gamma, z); | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -25,6 +25,53 @@ LL | offset_of!(Gamma, z); = help: the trait `Sized` is not implemented for `Extern` = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 3 previous errors +error[E0277]: the size for values of type `Extern` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:43:5 + | +LL | offset_of!(Delta<Extern>, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `Extern` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:44:5 + | +LL | offset_of!(Delta<dyn Trait>, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `dyn Trait` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `[u8]` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:42:5 + | +LL | offset_of!(Delta<Alpha>, z); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: within `Alpha`, the trait `Sized` is not implemented for `[u8]` +note: required because it appears within the type `Alpha` + --> $DIR/offset-of-dst-field.rs:5:8 + | +LL | struct Alpha { + | ^^^^^ + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0277]: the size for values of type `T` cannot be known at compilation time + --> $DIR/offset-of-dst-field.rs:48:5 + | +LL | fn generic_with_maybe_sized<T: ?Sized>() -> usize { + | - this type parameter needs to be `std::marker::Sized` +LL | offset_of!(Delta<T>, z) + | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider removing the `?Sized` bound to make the type parameter `Sized` + | +LL - fn generic_with_maybe_sized<T: ?Sized>() -> usize { +LL + fn generic_with_maybe_sized<T>() -> usize { + | + +error: aborting due to 7 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/offset-of/offset-of-inference.rs b/tests/ui/offset-of/offset-of-inference.rs new file mode 100644 index 00000000000..ba87574eae0 --- /dev/null +++ b/tests/ui/offset-of/offset-of-inference.rs @@ -0,0 +1,11 @@ +// Test that inference types in `offset_of!` don't ICE. + +#![feature(offset_of)] + +struct Foo<T> { + x: T, +} + +fn main() { + let _ = core::mem::offset_of!(Foo<_>, x); //~ ERROR: type annotations needed +} diff --git a/tests/ui/offset-of/offset-of-inference.stderr b/tests/ui/offset-of/offset-of-inference.stderr new file mode 100644 index 00000000000..2a520f6f906 --- /dev/null +++ b/tests/ui/offset-of/offset-of-inference.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/offset-of-inference.rs:10:35 + | +LL | let _ = core::mem::offset_of!(Foo<_>, x); + | ^^^^^^ cannot infer type + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/offset-of/offset-of-output-type.rs b/tests/ui/offset-of/offset-of-output-type.rs new file mode 100644 index 00000000000..50c2e93841f --- /dev/null +++ b/tests/ui/offset-of/offset-of-output-type.rs @@ -0,0 +1,20 @@ +#![feature(offset_of)] + +use std::mem::offset_of; + +struct S { + v: u8, + w: u16, +} + + +fn main() { + let _: u8 = offset_of!(S, v); //~ ERROR mismatched types + let _: u16 = offset_of!(S, v); //~ ERROR mismatched types + let _: u32 = offset_of!(S, v); //~ ERROR mismatched types + let _: u64 = offset_of!(S, v); //~ ERROR mismatched types + let _: isize = offset_of!(S, v); //~ ERROR mismatched types + let _: usize = offset_of!(S, v); + + offset_of!(S, v) //~ ERROR mismatched types +} diff --git a/tests/ui/offset-of/offset-of-output-type.stderr b/tests/ui/offset-of/offset-of-output-type.stderr new file mode 100644 index 00000000000..6f8c9475029 --- /dev/null +++ b/tests/ui/offset-of/offset-of-output-type.stderr @@ -0,0 +1,64 @@ +error[E0308]: mismatched types + --> $DIR/offset-of-output-type.rs:12:17 + | +LL | let _: u8 = offset_of!(S, v); + | -- ^^^^^^^^^^^^^^^^ expected `u8`, found `usize` + | | + | expected due to this + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/offset-of-output-type.rs:13:18 + | +LL | let _: u16 = offset_of!(S, v); + | --- ^^^^^^^^^^^^^^^^ expected `u16`, found `usize` + | | + | expected due to this + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/offset-of-output-type.rs:14:18 + | +LL | let _: u32 = offset_of!(S, v); + | --- ^^^^^^^^^^^^^^^^ expected `u32`, found `usize` + | | + | expected due to this + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/offset-of-output-type.rs:15:18 + | +LL | let _: u64 = offset_of!(S, v); + | --- ^^^^^^^^^^^^^^^^ expected `u64`, found `usize` + | | + | expected due to this + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/offset-of-output-type.rs:16:20 + | +LL | let _: isize = offset_of!(S, v); + | ----- ^^^^^^^^^^^^^^^^ expected `isize`, found `usize` + | | + | expected due to this + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/offset-of-output-type.rs:19:5 + | +LL | fn main() { + | - expected `()` because of default return type +... +LL | offset_of!(S, v) + | ^^^^^^^^^^^^^^^^ expected `()`, found `usize` + | + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/offset-of/offset-of-private.rs b/tests/ui/offset-of/offset-of-private.rs index 0291b7825ca..6b1a16ba62b 100644 --- a/tests/ui/offset-of/offset-of-private.rs +++ b/tests/ui/offset-of/offset-of-private.rs @@ -8,9 +8,21 @@ mod m { pub public: u8, private: u8, } + #[repr(C)] + pub struct FooTuple(pub u8, u8); + #[repr(C)] + struct Bar { + pub public: u8, + private: u8, + } } fn main() { offset_of!(m::Foo, public); offset_of!(m::Foo, private); //~ ERROR field `private` of struct `Foo` is private + offset_of!(m::FooTuple, 0); + offset_of!(m::FooTuple, 1); //~ ERROR field `1` of struct `FooTuple` is private + offset_of!(m::Bar, public); //~ ERROR struct `Bar` is private + offset_of!(m::Bar, private); //~ ERROR struct `Bar` is private + //~| ERROR field `private` of struct `Bar` is private } diff --git a/tests/ui/offset-of/offset-of-private.stderr b/tests/ui/offset-of/offset-of-private.stderr index 8a186dd5a02..0674b58f860 100644 --- a/tests/ui/offset-of/offset-of-private.stderr +++ b/tests/ui/offset-of/offset-of-private.stderr @@ -1,9 +1,46 @@ +error[E0603]: struct `Bar` is private + --> $DIR/offset-of-private.rs:25:19 + | +LL | offset_of!(m::Bar, public); + | ^^^ private struct + | +note: the struct `Bar` is defined here + --> $DIR/offset-of-private.rs:14:5 + | +LL | struct Bar { + | ^^^^^^^^^^ + +error[E0603]: struct `Bar` is private + --> $DIR/offset-of-private.rs:26:19 + | +LL | offset_of!(m::Bar, private); + | ^^^ private struct + | +note: the struct `Bar` is defined here + --> $DIR/offset-of-private.rs:14:5 + | +LL | struct Bar { + | ^^^^^^^^^^ + error[E0616]: field `private` of struct `Foo` is private - --> $DIR/offset-of-private.rs:15:24 + --> $DIR/offset-of-private.rs:22:24 | LL | offset_of!(m::Foo, private); | ^^^^^^^ private field -error: aborting due to previous error +error[E0616]: field `1` of struct `FooTuple` is private + --> $DIR/offset-of-private.rs:24:29 + | +LL | offset_of!(m::FooTuple, 1); + | ^ private field + +error[E0616]: field `private` of struct `Bar` is private + --> $DIR/offset-of-private.rs:26:24 + | +LL | offset_of!(m::Bar, private); + | ^^^^^^^ private field + +error: aborting due to 5 previous errors -For more information about this error, try `rustc --explain E0616`. +Some errors have detailed explanations: E0603, E0616. +For more information about an error, try `rustc --explain E0603`. diff --git a/tests/ui/offset-of/offset-of-self.rs b/tests/ui/offset-of/offset-of-self.rs new file mode 100644 index 00000000000..dbeef0e74dc --- /dev/null +++ b/tests/ui/offset-of/offset-of-self.rs @@ -0,0 +1,58 @@ +#![feature(offset_of)] + +use std::mem::offset_of; + +struct C<T> { + v: T, + w: T, +} + +struct S { + v: u8, + w: u16, +} + +impl S { + fn v_offs() -> usize { + offset_of!(Self, v) + } + fn v_offs_wrong_syntax() { + offset_of!(Self, Self::v); //~ ERROR no rules expected the token `::` + offset_of!(S, Self); //~ ERROR expected identifier, found keyword `Self` + //~| no field `Self` on type `S` + } + fn offs_in_c() -> usize { + offset_of!(C<Self>, w) + } + fn offs_in_c_colon() -> usize { + offset_of!(C::<Self>, w) + } +} + +mod m { + use std::mem::offset_of; + fn off() { + offset_of!(self::S, v); //~ ERROR cannot find type `S` in module + offset_of!(super::S, v); + offset_of!(crate::S, v); + } + impl super::n::T { + fn v_offs_self() -> usize { + offset_of!(Self, v) //~ ERROR field `v` of struct `T` is private + } + } +} + +mod n { + pub struct T { v: u8, } +} + +fn main() { + offset_of!(self::S, v); + offset_of!(Self, v); //~ ERROR cannot find type `Self` in this scope + + offset_of!(S, self); //~ ERROR expected identifier, found keyword `self` + //~| no field `self` on type `S` + offset_of!(S, v.self); //~ ERROR expected identifier, found keyword `self` + //~| no field `self` on type `u8` +} diff --git a/tests/ui/offset-of/offset-of-self.stderr b/tests/ui/offset-of/offset-of-self.stderr new file mode 100644 index 00000000000..df555463f98 --- /dev/null +++ b/tests/ui/offset-of/offset-of-self.stderr @@ -0,0 +1,79 @@ +error: no rules expected the token `::` + --> $DIR/offset-of-self.rs:20:30 + | +LL | offset_of!(Self, Self::v); + | ^^ no rules expected this token in macro call + | + = note: while trying to match sequence start + +error: expected identifier, found keyword `Self` + --> $DIR/offset-of-self.rs:21:23 + | +LL | offset_of!(S, Self); + | ^^^^ expected identifier, found keyword + +error: expected identifier, found keyword `self` + --> $DIR/offset-of-self.rs:54:19 + | +LL | offset_of!(S, self); + | ^^^^ expected identifier, found keyword + +error: expected identifier, found keyword `self` + --> $DIR/offset-of-self.rs:56:21 + | +LL | offset_of!(S, v.self); + | ^^^^ expected identifier, found keyword + +error[E0412]: cannot find type `S` in module `self` + --> $DIR/offset-of-self.rs:35:26 + | +LL | offset_of!(self::S, v); + | ^ not found in `self` + | +help: consider importing this struct + | +LL + use S; + | +help: if you import `S`, refer to it directly + | +LL - offset_of!(self::S, v); +LL + offset_of!(S, v); + | + +error[E0411]: cannot find type `Self` in this scope + --> $DIR/offset-of-self.rs:52:16 + | +LL | fn main() { + | ---- `Self` not allowed in a function +LL | offset_of!(self::S, v); +LL | offset_of!(Self, v); + | ^^^^ `Self` is only available in impls, traits, and type definitions + +error[E0609]: no field `Self` on type `S` + --> $DIR/offset-of-self.rs:21:23 + | +LL | offset_of!(S, Self); + | ^^^^ + +error[E0616]: field `v` of struct `T` is private + --> $DIR/offset-of-self.rs:41:30 + | +LL | offset_of!(Self, v) + | ^ private field + +error[E0609]: no field `self` on type `S` + --> $DIR/offset-of-self.rs:54:19 + | +LL | offset_of!(S, self); + | ^^^^ + +error[E0609]: no field `self` on type `u8` + --> $DIR/offset-of-self.rs:56:21 + | +LL | offset_of!(S, v.self); + | ^^^^ + +error: aborting due to 10 previous errors + +Some errors have detailed explanations: E0411, E0412, E0609, E0616. +For more information about an error, try `rustc --explain E0411`. diff --git a/tests/ui/or-patterns/or-patterns-default-binding-modes.rs b/tests/ui/or-patterns/or-patterns-default-binding-modes.rs index e56f9ffe23c..df6aab0e6a8 100644 --- a/tests/ui/or-patterns/or-patterns-default-binding-modes.rs +++ b/tests/ui/or-patterns/or-patterns-default-binding-modes.rs @@ -3,6 +3,8 @@ // check-pass #![allow(irrefutable_let_patterns)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] fn main() { // A regression test for a mistake we made at one point: diff --git a/tests/ui/panics/default-backtrace-ice.stderr b/tests/ui/panics/default-backtrace-ice.stderr index ddbfc4e7f3a..815ce4dd015 100644 --- a/tests/ui/panics/default-backtrace-ice.stderr +++ b/tests/ui/panics/default-backtrace-ice.stderr @@ -8,6 +8,8 @@ LL | fn main() { missing_ident; } stack backtrace: (end_short_backtrace) (begin_short_backtrace) +(end_short_backtrace) +(begin_short_backtrace) error: the compiler unexpectedly panicked. this is a bug. diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.rs b/tests/ui/panics/short-ice-remove-middle-frames-2.rs new file mode 100644 index 00000000000..38a80f8b670 --- /dev/null +++ b/tests/ui/panics/short-ice-remove-middle-frames-2.rs @@ -0,0 +1,61 @@ +// compile-flags:-Cstrip=none +// run-fail +// check-run-results +// exec-env:RUST_BACKTRACE=1 +// ignore-android FIXME #17520 +// ignore-wasm no panic support +// ignore-openbsd no support for libbacktrace without filename +// ignore-emscripten no panic +// ignore-sgx Backtraces not symbolized +// ignore-fuchsia Backtraces not symbolized +// ignore-msvc the `__rust_{begin,end}_short_backtrace` symbols aren't reliable. + +/// This test case make sure that we can have multiple pairs of `__rust_{begin,end}_short_backtrace` + +#[inline(never)] +fn __rust_begin_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T { + let result = f(); + std::hint::black_box(result) +} + +#[inline(never)] +fn __rust_end_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T { + let result = f(); + std::hint::black_box(result) +} + +fn first() { + __rust_end_short_backtrace(|| second()); +} + +fn second() { + third(); // won't show up +} + +fn third() { + fourth(); // won't show up +} + +fn fourth() { + __rust_begin_short_backtrace(|| fifth()); +} + +fn fifth() { + __rust_end_short_backtrace(|| sixth()); +} + +fn sixth() { + seven(); // won't show up +} + +fn seven() { + __rust_begin_short_backtrace(|| eight()); +} + +fn eight() { + panic!("debug!!!"); +} + +fn main() { + first(); +} diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr new file mode 100644 index 00000000000..2592b747918 --- /dev/null +++ b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr @@ -0,0 +1,11 @@ +thread 'main' panicked at 'debug!!!', $DIR/short-ice-remove-middle-frames-2.rs:56:5 +stack backtrace: + 0: std::panicking::begin_panic + 1: short_ice_remove_middle_frames_2::eight + 2: short_ice_remove_middle_frames_2::seven::{{closure}} + 3: short_ice_remove_middle_frames_2::fifth + 4: short_ice_remove_middle_frames_2::fourth::{{closure}} + 5: short_ice_remove_middle_frames_2::first + 6: short_ice_remove_middle_frames_2::main + 7: core::ops::function::FnOnce::call_once +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/tests/ui/panics/short-ice-remove-middle-frames.rs b/tests/ui/panics/short-ice-remove-middle-frames.rs new file mode 100644 index 00000000000..c872084f033 --- /dev/null +++ b/tests/ui/panics/short-ice-remove-middle-frames.rs @@ -0,0 +1,57 @@ +// compile-flags:-Cstrip=none +// run-fail +// check-run-results +// exec-env:RUST_BACKTRACE=1 +// ignore-android FIXME #17520 +// ignore-wasm no panic support +// ignore-openbsd no support for libbacktrace without filename +// ignore-emscripten no panic +// ignore-sgx Backtraces not symbolized +// ignore-fuchsia Backtraces not symbolized +// ignore-msvc the `__rust_{begin,end}_short_backtrace` symbols aren't reliable. + + +#[inline(never)] +fn __rust_begin_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T { + let result = f(); + std::hint::black_box(result) +} + +#[inline(never)] +fn __rust_end_short_backtrace<T, F: FnOnce() -> T>(f: F) -> T { + let result = f(); + std::hint::black_box(result) +} + +fn first() { + __rust_end_short_backtrace(|| second()); + // do not take effect since we already has a inner call of __rust_end_short_backtrace +} + +fn second() { + __rust_end_short_backtrace(|| third()); +} + +fn third() { + fourth(); // won't show up in backtrace +} + +fn fourth() { + fifth(); // won't show up in backtrace +} + +fn fifth() { + __rust_begin_short_backtrace(|| sixth()); +} + +fn sixth() { + seven(); +} + +fn seven() { + panic!("debug!!!"); +} + +fn main() { + first(); +} diff --git a/tests/ui/panics/short-ice-remove-middle-frames.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr new file mode 100644 index 00000000000..9c15f2e08fe --- /dev/null +++ b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr @@ -0,0 +1,12 @@ +thread 'main' panicked at 'debug!!!', $DIR/short-ice-remove-middle-frames.rs:52:5 +stack backtrace: + 0: std::panicking::begin_panic + 1: short_ice_remove_middle_frames::seven + 2: short_ice_remove_middle_frames::sixth + 3: short_ice_remove_middle_frames::fifth::{{closure}} + 4: short_ice_remove_middle_frames::second + 5: short_ice_remove_middle_frames::first::{{closure}} + 6: short_ice_remove_middle_frames::first + 7: short_ice_remove_middle_frames::main + 8: core::ops::function::FnOnce::call_once +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/tests/ui/parser/dyn-trait-compatibility.stderr b/tests/ui/parser/dyn-trait-compatibility.stderr index 653be5b3b71..e34d855a9d4 100644 --- a/tests/ui/parser/dyn-trait-compatibility.stderr +++ b/tests/ui/parser/dyn-trait-compatibility.stderr @@ -1,9 +1,3 @@ -error[E0433]: failed to resolve: use of undeclared crate or module `dyn` - --> $DIR/dyn-trait-compatibility.rs:3:11 - | -LL | type A1 = dyn::dyn; - | ^^^ use of undeclared crate or module `dyn` - error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:1:11 | @@ -46,6 +40,12 @@ error[E0412]: cannot find type `dyn` in this scope LL | type A3 = dyn<<dyn as dyn>::dyn>; | ^^^ not found in this scope +error[E0433]: failed to resolve: use of undeclared crate or module `dyn` + --> $DIR/dyn-trait-compatibility.rs:3:11 + | +LL | type A1 = dyn::dyn; + | ^^^ use of undeclared crate or module `dyn` + error: aborting due to 8 previous errors Some errors have detailed explanations: E0405, E0412, E0433. diff --git a/tests/ui/parser/impl-on-unsized-typo.rs b/tests/ui/parser/impl-on-unsized-typo.rs new file mode 100644 index 00000000000..e09c0463045 --- /dev/null +++ b/tests/ui/parser/impl-on-unsized-typo.rs @@ -0,0 +1,6 @@ +trait Tr {} + +impl<T ?Sized> Tr for T {} +//~^ ERROR expected one of `,`, `:`, `=`, or `>`, found `?` + +fn main() {} diff --git a/tests/ui/parser/impl-on-unsized-typo.stderr b/tests/ui/parser/impl-on-unsized-typo.stderr new file mode 100644 index 00000000000..23dcc1efd68 --- /dev/null +++ b/tests/ui/parser/impl-on-unsized-typo.stderr @@ -0,0 +1,8 @@ +error: expected one of `,`, `:`, `=`, or `>`, found `?` + --> $DIR/impl-on-unsized-typo.rs:3:8 + | +LL | impl<T ?Sized> Tr for T {} + | ^ expected one of `,`, `:`, `=`, or `>` + +error: aborting due to previous error + diff --git a/tests/ui/parser/issues/issue-111416.rs b/tests/ui/parser/issues/issue-111416.rs new file mode 100644 index 00000000000..cfd1b6b99ba --- /dev/null +++ b/tests/ui/parser/issues/issue-111416.rs @@ -0,0 +1,3 @@ +fn main() { + let my = monad_bind(mx, T: Try); //~ ERROR invalid `struct` delimiters or `fn` call arguments +} diff --git a/tests/ui/parser/issues/issue-111416.stderr b/tests/ui/parser/issues/issue-111416.stderr new file mode 100644 index 00000000000..ddacf4d6dfc --- /dev/null +++ b/tests/ui/parser/issues/issue-111416.stderr @@ -0,0 +1,18 @@ +error: invalid `struct` delimiters or `fn` call arguments + --> $DIR/issue-111416.rs:2:14 + | +LL | let my = monad_bind(mx, T: Try); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: if `monad_bind` is a struct, use braces as delimiters + | +LL | let my = monad_bind { mx, T: Try }; + | ~ ~ +help: if `monad_bind` is a function, use the arguments directly + | +LL - let my = monad_bind(mx, T: Try); +LL + let my = monad_bind(mx, Try); + | + +error: aborting due to previous error + diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs index fbdefd9d36c..43b53b7cf1f 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-at-and-box-pass.rs @@ -2,6 +2,9 @@ // Test `@` patterns combined with `box` patterns. +#![allow(dropping_references)] +#![allow(dropping_copy_types)] + #![feature(box_patterns)] #[derive(Copy, Clone)] diff --git a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs index 0108861cfce..1df51c0edd9 100644 --- a/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs +++ b/tests/ui/pattern/bindings-after-at/borrowck-pat-by-copy-bindings-in-at.rs @@ -2,6 +2,8 @@ // Test `Copy` bindings in the rhs of `@` patterns. +#![allow(dropping_copy_types)] + #[derive(Copy, Clone)] struct C; diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs index 5445696fdff..204cd3e6657 100644 --- a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs +++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern-pass.rs @@ -1,5 +1,7 @@ // check-pass +#![allow(dropping_references)] + fn main() {} struct U; diff --git a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs index 583f70f41aa..4de1f653db0 100644 --- a/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs +++ b/tests/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-pass.rs @@ -1,5 +1,7 @@ // check-pass +#![allow(dropping_references)] + fn main() { struct U; fn accept_fn_once(_: impl FnOnce()) {} diff --git a/tests/ui/pattern/pattern-error-continue.stderr b/tests/ui/pattern/pattern-error-continue.stderr index e1349fb02ea..10fcccb0301 100644 --- a/tests/ui/pattern/pattern-error-continue.stderr +++ b/tests/ui/pattern/pattern-error-continue.stderr @@ -1,9 +1,3 @@ -error[E0433]: failed to resolve: use of undeclared type `E` - --> $DIR/pattern-error-continue.rs:33:9 - | -LL | E::V => {} - | ^ use of undeclared type `E` - error[E0532]: expected tuple struct or tuple variant, found unit variant `A::D` --> $DIR/pattern-error-continue.rs:18:9 | @@ -56,6 +50,15 @@ note: function defined here LL | fn f(_c: char) {} | ^ -------- +error[E0433]: failed to resolve: use of undeclared type `E` + --> $DIR/pattern-error-continue.rs:33:9 + | +LL | E::V => {} + | ^ + | | + | use of undeclared type `E` + | help: an enum with a similar name exists: `A` + error: aborting due to 5 previous errors Some errors have detailed explanations: E0023, E0308, E0433, E0532. diff --git a/tests/ui/pattern/usefulness/consts-opaque.rs b/tests/ui/pattern/usefulness/consts-opaque.rs index ca4fcd85bb6..c10c6205a08 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.rs +++ b/tests/ui/pattern/usefulness/consts-opaque.rs @@ -20,11 +20,12 @@ const BAR: Bar = Bar; #[derive(PartialEq)] enum Baz { Baz1, - Baz2 + Baz2, } impl Eq for Baz {} const BAZ: Baz = Baz::Baz1; +#[rustfmt::skip] fn main() { match FOO { FOO => {} @@ -124,8 +125,16 @@ fn main() { match WRAPQUUX { Wrap(_) => {} - WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer - //~^ ERROR unreachable pattern + WRAPQUUX => {} + } + + match WRAPQUUX { + Wrap(_) => {} + } + + match WRAPQUUX { + //~^ ERROR: non-exhaustive patterns: `Wrap(_)` not covered + WRAPQUUX => {} } #[derive(PartialEq, Eq)] @@ -138,8 +147,7 @@ fn main() { match WHOKNOWSQUUX { WHOKNOWSQUUX => {} WhoKnows::Yay(_) => {} - WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer - //~^ ERROR unreachable pattern + WHOKNOWSQUUX => {} WhoKnows::Nope => {} } } diff --git a/tests/ui/pattern/usefulness/consts-opaque.stderr b/tests/ui/pattern/usefulness/consts-opaque.stderr index 3f0b4a9f26a..e01b06ccc82 100644 --- a/tests/ui/pattern/usefulness/consts-opaque.stderr +++ b/tests/ui/pattern/usefulness/consts-opaque.stderr @@ -1,5 +1,5 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:30:9 + --> $DIR/consts-opaque.rs:31:9 | LL | FOO => {} | ^^^ @@ -8,7 +8,7 @@ LL | FOO => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:37:9 + --> $DIR/consts-opaque.rs:38:9 | LL | FOO_REF => {} | ^^^^^^^ @@ -17,7 +17,7 @@ LL | FOO_REF => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details warning: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:45:9 + --> $DIR/consts-opaque.rs:46:9 | LL | FOO_REF_REF => {} | ^^^^^^^^^^^ @@ -29,7 +29,7 @@ LL | FOO_REF_REF => {} = note: `#[warn(indirect_structural_match)]` on by default error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:53:9 + --> $DIR/consts-opaque.rs:54:9 | LL | BAR => {} // should not be emitting unreachable warning | ^^^ @@ -38,7 +38,7 @@ LL | BAR => {} // should not be emitting unreachable warning = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:61:9 + --> $DIR/consts-opaque.rs:62:9 | LL | BAR => {} | ^^^ @@ -47,7 +47,7 @@ LL | BAR => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:70:9 + --> $DIR/consts-opaque.rs:71:9 | LL | BAR => {} | ^^^ @@ -56,7 +56,7 @@ LL | BAR => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Bar` in a pattern, `Bar` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:72:9 + --> $DIR/consts-opaque.rs:73:9 | LL | BAR => {} // should not be emitting unreachable warning | ^^^ @@ -65,7 +65,7 @@ LL | BAR => {} // should not be emitting unreachable warning = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:80:9 + --> $DIR/consts-opaque.rs:81:9 | LL | BAZ => {} | ^^^ @@ -74,7 +74,7 @@ LL | BAZ => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:90:9 + --> $DIR/consts-opaque.rs:91:9 | LL | BAZ => {} | ^^^ @@ -83,7 +83,7 @@ LL | BAZ => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: to use a constant of type `Baz` in a pattern, `Baz` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/consts-opaque.rs:97:9 + --> $DIR/consts-opaque.rs:98:9 | LL | BAZ => {} | ^^^ @@ -92,7 +92,7 @@ LL | BAZ => {} = note: see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details error: unreachable pattern - --> $DIR/consts-opaque.rs:32:9 + --> $DIR/consts-opaque.rs:33:9 | LL | FOO => {} | --- matches any value @@ -107,7 +107,7 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/consts-opaque.rs:39:9 + --> $DIR/consts-opaque.rs:40:9 | LL | FOO_REF => {} | ------- matches any value @@ -116,7 +116,7 @@ LL | Foo(_) => {} // should not be emitting unreachable warning | ^^^^^^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:53:9 + --> $DIR/consts-opaque.rs:54:9 | LL | Bar => {} | --- matches any value @@ -124,7 +124,7 @@ LL | BAR => {} // should not be emitting unreachable warning | ^^^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:56:9 + --> $DIR/consts-opaque.rs:57:9 | LL | Bar => {} | --- matches any value @@ -133,7 +133,7 @@ LL | _ => {} | ^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:63:9 + --> $DIR/consts-opaque.rs:64:9 | LL | BAR => {} | --- matches any value @@ -142,7 +142,7 @@ LL | Bar => {} // should not be emitting unreachable warning | ^^^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:65:9 + --> $DIR/consts-opaque.rs:66:9 | LL | BAR => {} | --- matches any value @@ -151,7 +151,7 @@ LL | _ => {} | ^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:72:9 + --> $DIR/consts-opaque.rs:73:9 | LL | BAR => {} | --- matches any value @@ -160,7 +160,7 @@ LL | BAR => {} // should not be emitting unreachable warning | ^^^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:75:9 + --> $DIR/consts-opaque.rs:76:9 | LL | BAR => {} | --- matches any value @@ -169,7 +169,7 @@ LL | _ => {} // should not be emitting unreachable warning | ^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:82:9 + --> $DIR/consts-opaque.rs:83:9 | LL | BAZ => {} | --- matches any value @@ -178,7 +178,7 @@ LL | Baz::Baz1 => {} // should not be emitting unreachable warning | ^^^^^^^^^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:84:9 + --> $DIR/consts-opaque.rs:85:9 | LL | BAZ => {} | --- matches any value @@ -187,7 +187,7 @@ LL | _ => {} | ^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:92:9 + --> $DIR/consts-opaque.rs:93:9 | LL | BAZ => {} | --- matches any value @@ -196,7 +196,7 @@ LL | _ => {} | ^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:99:9 + --> $DIR/consts-opaque.rs:100:9 | LL | BAZ => {} | --- matches any value @@ -205,7 +205,7 @@ LL | Baz::Baz2 => {} // should not be emitting unreachable warning | ^^^^^^^^^ unreachable pattern error: unreachable pattern - --> $DIR/consts-opaque.rs:101:9 + --> $DIR/consts-opaque.rs:102:9 | LL | BAZ => {} | --- matches any value @@ -213,19 +213,24 @@ LL | BAZ => {} LL | _ => {} // should not be emitting unreachable warning | ^ unreachable pattern -error: unreachable pattern - --> $DIR/consts-opaque.rs:127:9 +error[E0004]: non-exhaustive patterns: `Wrap(_)` not covered + --> $DIR/consts-opaque.rs:135:11 | -LL | Wrap(_) => {} - | ------- matches any value -LL | WRAPQUUX => {} // detected unreachable because we do inspect the `Wrap` layer - | ^^^^^^^^ unreachable pattern - -error: unreachable pattern - --> $DIR/consts-opaque.rs:141:9 +LL | match WRAPQUUX { + | ^^^^^^^^ pattern `Wrap(_)` not covered + | +note: `Wrap<fn(usize, usize) -> usize>` defined here + --> $DIR/consts-opaque.rs:117:12 + | +LL | struct Wrap<T>(T); + | ^^^^ + = note: the matched value is of type `Wrap<fn(usize, usize) -> usize>` +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ WRAPQUUX => {}, +LL + Wrap(_) => todo!() | -LL | WHOKNOWSQUUX => {} // detected unreachable because we do inspect the `WhoKnows` layer - | ^^^^^^^^^^^^ -error: aborting due to 24 previous errors; 1 warning emitted +error: aborting due to 23 previous errors; 1 warning emitted +For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/print_type_sizes/async.rs b/tests/ui/print_type_sizes/async.rs index 1598b069691..f38a6e674da 100644 --- a/tests/ui/print_type_sizes/async.rs +++ b/tests/ui/print_type_sizes/async.rs @@ -3,6 +3,8 @@ // build-pass // ignore-pass +#![allow(dropping_copy_types)] + async fn wait() {} pub async fn test(arg: [u8; 8192]) { diff --git a/tests/ui/print_type_sizes/async.stdout b/tests/ui/print_type_sizes/async.stdout index 1c6887412be..873def9031a 100644 --- a/tests/ui/print_type_sizes/async.stdout +++ b/tests/ui/print_type_sizes/async.stdout @@ -1,4 +1,4 @@ -print-type-size type: `[async fn body@$DIR/async.rs:8:36: 11:2]`: 16386 bytes, alignment: 1 bytes +print-type-size type: `[async fn body@$DIR/async.rs:10:36: 13:2]`: 16386 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 8192 bytes print-type-size upvar `.arg`: 8192 bytes @@ -16,14 +16,14 @@ print-type-size type: `std::mem::MaybeUninit<[u8; 8192]>`: 8192 bytes, alignment print-type-size variant `MaybeUninit`: 8192 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 8192 bytes -print-type-size type: `[async fn body@$DIR/async.rs:6:17: 6:19]`: 1 bytes, alignment: 1 bytes +print-type-size type: `[async fn body@$DIR/async.rs:8:17: 8:19]`: 1 bytes, alignment: 1 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Returned`: 0 bytes print-type-size variant `Panicked`: 0 bytes -print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:6:17: 6:19]>`: 1 bytes, alignment: 1 bytes +print-type-size type: `std::mem::ManuallyDrop<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes print-type-size field `.value`: 1 bytes -print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:6:17: 6:19]>`: 1 bytes, alignment: 1 bytes +print-type-size type: `std::mem::MaybeUninit<[async fn body@$DIR/async.rs:8:17: 8:19]>`: 1 bytes, alignment: 1 bytes print-type-size variant `MaybeUninit`: 1 bytes print-type-size field `.uninit`: 0 bytes print-type-size field `.value`: 1 bytes diff --git a/tests/ui/print_type_sizes/generator_discr_placement.rs b/tests/ui/print_type_sizes/generator_discr_placement.rs index 1a85fe95bb6..6adc14f9b99 100644 --- a/tests/ui/print_type_sizes/generator_discr_placement.rs +++ b/tests/ui/print_type_sizes/generator_discr_placement.rs @@ -6,6 +6,7 @@ // Avoid emitting panic handlers, like the rest of these tests... #![feature(generators)] +#![allow(dropping_copy_types)] pub fn foo() { let a = || { diff --git a/tests/ui/print_type_sizes/generator_discr_placement.stdout b/tests/ui/print_type_sizes/generator_discr_placement.stdout index f2a11c7a33b..fe0022cf5f4 100644 --- a/tests/ui/print_type_sizes/generator_discr_placement.stdout +++ b/tests/ui/print_type_sizes/generator_discr_placement.stdout @@ -1,4 +1,4 @@ -print-type-size type: `[generator@$DIR/generator_discr_placement.rs:11:13: 11:15]`: 8 bytes, alignment: 4 bytes +print-type-size type: `[generator@$DIR/generator_discr_placement.rs:12:13: 12:15]`: 8 bytes, alignment: 4 bytes print-type-size discriminant: 1 bytes print-type-size variant `Unresumed`: 0 bytes print-type-size variant `Suspend0`: 7 bytes diff --git a/tests/ui/regions/type-param-outlives-reempty-issue-74429-2.rs b/tests/ui/regions/type-param-outlives-reempty-issue-74429-2.rs index a65c17e0efc..5ae5ebb450e 100644 --- a/tests/ui/regions/type-param-outlives-reempty-issue-74429-2.rs +++ b/tests/ui/regions/type-param-outlives-reempty-issue-74429-2.rs @@ -55,11 +55,11 @@ where } pub fn x<T: Copy>(a: Array<T>) { - // drop just avoids a must_use warning - drop((0..1).filter(|_| true)); + // _ just avoids a must_use warning + let _ = (0..1).filter(|_| true); let y = a.index_axis(); a.axis_iter().for_each(|_| { - drop(y); + let _ = y; }); } diff --git a/tests/ui/regions/type-param-outlives-reempty-issue-74429.rs b/tests/ui/regions/type-param-outlives-reempty-issue-74429.rs index d463f311c34..0c1e9314441 100644 --- a/tests/ui/regions/type-param-outlives-reempty-issue-74429.rs +++ b/tests/ui/regions/type-param-outlives-reempty-issue-74429.rs @@ -3,6 +3,8 @@ // check-pass +#![allow(dropping_copy_types)] + use std::marker::PhantomData; fn apply<T, F: FnOnce(T)>(_: T, _: F) {} diff --git a/tests/ui/resolve/issue-109250.rs b/tests/ui/resolve/issue-109250.rs new file mode 100644 index 00000000000..68e33f693ce --- /dev/null +++ b/tests/ui/resolve/issue-109250.rs @@ -0,0 +1,3 @@ +fn main() { //~ HELP consider importing + HashMap::new; //~ ERROR failed to resolve: use of undeclared type `HashMap` +} diff --git a/tests/ui/resolve/issue-109250.stderr b/tests/ui/resolve/issue-109250.stderr new file mode 100644 index 00000000000..d5b8c08ced7 --- /dev/null +++ b/tests/ui/resolve/issue-109250.stderr @@ -0,0 +1,14 @@ +error[E0433]: failed to resolve: use of undeclared type `HashMap` + --> $DIR/issue-109250.rs:2:5 + | +LL | HashMap::new; + | ^^^^^^^ use of undeclared type `HashMap` + | +help: consider importing this struct + | +LL + use std::collections::HashMap; + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0433`. diff --git a/tests/ui/resolve/issue-111312.rs b/tests/ui/resolve/issue-111312.rs new file mode 100644 index 00000000000..acea37b358b --- /dev/null +++ b/tests/ui/resolve/issue-111312.rs @@ -0,0 +1,11 @@ +// edition: 2021 + +trait Has { + fn has() {} +} + +trait HasNot {} + +fn main() { + HasNot::has(); //~ ERROR +} diff --git a/tests/ui/resolve/issue-111312.stderr b/tests/ui/resolve/issue-111312.stderr new file mode 100644 index 00000000000..4c864029c98 --- /dev/null +++ b/tests/ui/resolve/issue-111312.stderr @@ -0,0 +1,15 @@ +error[E0599]: no function or associated item named `has` found for trait `HasNot` + --> $DIR/issue-111312.rs:10:13 + | +LL | HasNot::has(); + | ^^^ function or associated item not found in `HasNot` + | +note: `Has` defines an item `has` + --> $DIR/issue-111312.rs:3:1 + | +LL | trait Has { + | ^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/resolve/issue-111727.rs b/tests/ui/resolve/issue-111727.rs new file mode 100644 index 00000000000..36f3081211d --- /dev/null +++ b/tests/ui/resolve/issue-111727.rs @@ -0,0 +1,5 @@ +// edition: 2021 + +fn main() { + std::any::Any::create(); //~ ERROR +} diff --git a/tests/ui/resolve/issue-111727.stderr b/tests/ui/resolve/issue-111727.stderr new file mode 100644 index 00000000000..bd748211ed3 --- /dev/null +++ b/tests/ui/resolve/issue-111727.stderr @@ -0,0 +1,9 @@ +error[E0599]: no function or associated item named `create` found for trait `Any` + --> $DIR/issue-111727.rs:4:20 + | +LL | std::any::Any::create(); + | ^^^^^^ function or associated item not found in `Any` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/resolve/issue-50599.rs b/tests/ui/resolve/issue-50599.rs index 72238a59198..00588735b9a 100644 --- a/tests/ui/resolve/issue-50599.rs +++ b/tests/ui/resolve/issue-50599.rs @@ -2,5 +2,4 @@ fn main() { const N: u32 = 1_000; const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize; //~ ERROR cannot find value let mut digits = [0u32; M]; - //~^ constant } diff --git a/tests/ui/resolve/issue-50599.stderr b/tests/ui/resolve/issue-50599.stderr index d7419b64fac..d58b6ca5b5c 100644 --- a/tests/ui/resolve/issue-50599.stderr +++ b/tests/ui/resolve/issue-50599.stderr @@ -16,12 +16,6 @@ LL - const M: usize = (f64::from(N) * std::f64::LOG10_2) as usize; LL + const M: usize = (f64::from(N) * LOG10_2) as usize; | -note: erroneous constant used - --> $DIR/issue-50599.rs:4:29 - | -LL | let mut digits = [0u32; M]; - | ^ - error: aborting due to previous error For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/resolve/resolve-variant-assoc-item.stderr b/tests/ui/resolve/resolve-variant-assoc-item.stderr index 4be1019968b..ed157197d17 100644 --- a/tests/ui/resolve/resolve-variant-assoc-item.stderr +++ b/tests/ui/resolve/resolve-variant-assoc-item.stderr @@ -3,12 +3,26 @@ error[E0433]: failed to resolve: `V` is a variant, not a module | LL | E::V::associated_item; | ^ `V` is a variant, not a module + | +help: there is an enum variant `E::V`; try using the variant's enum + | +LL | E; + | ~ error[E0433]: failed to resolve: `V` is a variant, not a module --> $DIR/resolve-variant-assoc-item.rs:6:5 | LL | V::associated_item; | ^ `V` is a variant, not a module + | +help: there is an enum variant `E::V`; try using the variant's enum + | +LL | E; + | ~ +help: an enum with a similar name exists + | +LL | E::associated_item; + | ~ error: aborting due to 2 previous errors diff --git a/tests/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs b/tests/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs index be775b37f7b..b9ff24c7624 100644 --- a/tests/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs +++ b/tests/ui/rfc-2008-non-exhaustive/borrowck-exhaustive.rs @@ -3,6 +3,8 @@ // check-pass +#![allow(dropping_references)] + // aux-build:monovariants.rs extern crate monovariants; diff --git a/tests/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs b/tests/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs index 04d924a9aed..542be3942b7 100644 --- a/tests/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs +++ b/tests/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.rs @@ -4,6 +4,8 @@ // Tests ensuring that `dbg!(expr)` has the expected run-time behavior. // as well as some compile time properties we expect. +#![allow(dropping_copy_types)] + #[derive(Copy, Clone, Debug)] struct Unit; diff --git a/tests/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr b/tests/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr index 49d72158e92..a20a6062c13 100644 --- a/tests/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr +++ b/tests/ui/rfc-2361-dbg-macro/dbg-macro-expected-behavior.run.stderr @@ -1,28 +1,28 @@ -[$DIR/dbg-macro-expected-behavior.rs:20] Unit = Unit -[$DIR/dbg-macro-expected-behavior.rs:21] a = Unit -[$DIR/dbg-macro-expected-behavior.rs:27] Point { x: 42, y: 24 } = Point { +[$DIR/dbg-macro-expected-behavior.rs:22] Unit = Unit +[$DIR/dbg-macro-expected-behavior.rs:23] a = Unit +[$DIR/dbg-macro-expected-behavior.rs:29] Point { x: 42, y: 24 } = Point { x: 42, y: 24, } -[$DIR/dbg-macro-expected-behavior.rs:28] b = Point { +[$DIR/dbg-macro-expected-behavior.rs:30] b = Point { x: 42, y: 24, } -[$DIR/dbg-macro-expected-behavior.rs:36] -[$DIR/dbg-macro-expected-behavior.rs:40] &a = NoCopy( +[$DIR/dbg-macro-expected-behavior.rs:38] +[$DIR/dbg-macro-expected-behavior.rs:42] &a = NoCopy( 1337, ) -[$DIR/dbg-macro-expected-behavior.rs:40] dbg!(& a) = NoCopy( +[$DIR/dbg-macro-expected-behavior.rs:42] dbg!(& a) = NoCopy( 1337, ) -[$DIR/dbg-macro-expected-behavior.rs:45] f(&42) = 42 +[$DIR/dbg-macro-expected-behavior.rs:47] f(&42) = 42 before -[$DIR/dbg-macro-expected-behavior.rs:50] { foo += 1; eprintln!("before"); 7331 } = 7331 -[$DIR/dbg-macro-expected-behavior.rs:58] ("Yeah",) = ( +[$DIR/dbg-macro-expected-behavior.rs:52] { foo += 1; eprintln!("before"); 7331 } = 7331 +[$DIR/dbg-macro-expected-behavior.rs:60] ("Yeah",) = ( "Yeah", ) -[$DIR/dbg-macro-expected-behavior.rs:61] 1 = 1 -[$DIR/dbg-macro-expected-behavior.rs:61] 2 = 2 -[$DIR/dbg-macro-expected-behavior.rs:65] 1u8 = 1 -[$DIR/dbg-macro-expected-behavior.rs:65] 2u32 = 2 -[$DIR/dbg-macro-expected-behavior.rs:65] "Yeah" = "Yeah" +[$DIR/dbg-macro-expected-behavior.rs:63] 1 = 1 +[$DIR/dbg-macro-expected-behavior.rs:63] 2 = 2 +[$DIR/dbg-macro-expected-behavior.rs:67] 1u8 = 1 +[$DIR/dbg-macro-expected-behavior.rs:67] 2u32 = 2 +[$DIR/dbg-macro-expected-behavior.rs:67] "Yeah" = "Yeah" diff --git a/tests/ui/rust-2018/remove-extern-crate.fixed b/tests/ui/rust-2018/remove-extern-crate.fixed index 15e0ccc5256..209b91af1dd 100644 --- a/tests/ui/rust-2018/remove-extern-crate.fixed +++ b/tests/ui/rust-2018/remove-extern-crate.fixed @@ -5,6 +5,7 @@ // compile-flags:--extern remove_extern_crate #![warn(rust_2018_idioms)] +#![allow(dropping_copy_types)] //~ WARNING unused extern crate // Shouldn't suggest changing to `use`, as `another_name` diff --git a/tests/ui/rust-2018/remove-extern-crate.rs b/tests/ui/rust-2018/remove-extern-crate.rs index aec0bc7c374..ef3c2db696a 100644 --- a/tests/ui/rust-2018/remove-extern-crate.rs +++ b/tests/ui/rust-2018/remove-extern-crate.rs @@ -5,6 +5,7 @@ // compile-flags:--extern remove_extern_crate #![warn(rust_2018_idioms)] +#![allow(dropping_copy_types)] extern crate core; //~ WARNING unused extern crate // Shouldn't suggest changing to `use`, as `another_name` diff --git a/tests/ui/rust-2018/remove-extern-crate.stderr b/tests/ui/rust-2018/remove-extern-crate.stderr index d07358e471b..f752cac8ed6 100644 --- a/tests/ui/rust-2018/remove-extern-crate.stderr +++ b/tests/ui/rust-2018/remove-extern-crate.stderr @@ -1,5 +1,5 @@ warning: unused extern crate - --> $DIR/remove-extern-crate.rs:9:1 + --> $DIR/remove-extern-crate.rs:10:1 | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ help: remove it @@ -12,7 +12,7 @@ LL | #![warn(rust_2018_idioms)] = note: `#[warn(unused_extern_crates)]` implied by `#[warn(rust_2018_idioms)]` warning: `extern crate` is not idiomatic in the new edition - --> $DIR/remove-extern-crate.rs:33:5 + --> $DIR/remove-extern-crate.rs:34:5 | LL | extern crate core; | ^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | use core; | ~~~ warning: `extern crate` is not idiomatic in the new edition - --> $DIR/remove-extern-crate.rs:43:5 + --> $DIR/remove-extern-crate.rs:44:5 | LL | pub extern crate core; | ^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/self/arbitrary-self-types-not-object-safe.curr.stderr b/tests/ui/self/arbitrary-self-types-not-object-safe.curr.stderr index 0ec0d4be5f2..13591f5b635 100644 --- a/tests/ui/self/arbitrary-self-types-not-object-safe.curr.stderr +++ b/tests/ui/self/arbitrary-self-types-not-object-safe.curr.stderr @@ -31,8 +31,7 @@ LL | trait Foo { | --- this trait cannot be made into an object... LL | fn foo(self: &Rc<Self>) -> usize; | ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on - = note: required for `Rc<usize>` to implement `CoerceUnsized<Rc<dyn Foo>>` - = note: required by cast to type `Rc<dyn Foo>` + = note: required for the cast from `Rc<usize>` to `Rc<dyn Foo>` error: aborting due to 2 previous errors diff --git a/tests/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr b/tests/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr index b494b448e2e..593f705353a 100644 --- a/tests/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr +++ b/tests/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr @@ -14,8 +14,7 @@ LL | trait Foo { | --- this trait cannot be made into an object... LL | fn foo(self: &Rc<Self>) -> usize; | ^^^^^^^^^ ...because method `foo`'s `self` parameter cannot be dispatched on - = note: required for `Rc<usize>` to implement `CoerceUnsized<Rc<dyn Foo>>` - = note: required by cast to type `Rc<dyn Foo>` + = note: required for the cast from `Rc<usize>` to `Rc<dyn Foo>` error: aborting due to previous error diff --git a/tests/ui/self/self-ctor-inner-const.rs b/tests/ui/self/self-ctor-inner-const.rs deleted file mode 100644 index b015397a5bc..00000000000 --- a/tests/ui/self/self-ctor-inner-const.rs +++ /dev/null @@ -1,17 +0,0 @@ -// Verify that we ban usage of `Self` as constructor from inner items. - -struct S0<T>(T); - -impl<T> S0<T> { - fn foo() { - const C: S0<u8> = Self(0); - //~^ ERROR can't use generic parameters from outer function - fn bar() -> Self { - //~^ ERROR can't use generic parameters from outer function - Self(0) - //~^ ERROR can't use generic parameters from outer function - } - } -} - -fn main() {} diff --git a/tests/ui/self/self-ctor-inner-const.stderr b/tests/ui/self/self-ctor-inner-const.stderr deleted file mode 100644 index 7287c64c659..00000000000 --- a/tests/ui/self/self-ctor-inner-const.stderr +++ /dev/null @@ -1,33 +0,0 @@ -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-ctor-inner-const.rs:7:27 - | -LL | const C: S0<u8> = Self(0); - | ^^^^ - | | - | use of generic parameter from outer function - | can't use `Self` here - -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-ctor-inner-const.rs:9:21 - | -LL | impl<T> S0<T> { - | ---- `Self` type implicitly declared here, by this `impl` -... -LL | fn bar() -> Self { - | ^^^^ - | | - | use of generic parameter from outer function - | use a type here instead - -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-ctor-inner-const.rs:11:13 - | -LL | Self(0) - | ^^^^ - | | - | use of generic parameter from outer function - | can't use `Self` here - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0401`. diff --git a/tests/ui/self/self-ctor-nongeneric.rs b/tests/ui/self/self-ctor-nongeneric.rs new file mode 100644 index 00000000000..0ae7f8da4b4 --- /dev/null +++ b/tests/ui/self/self-ctor-nongeneric.rs @@ -0,0 +1,15 @@ +// `Self` as a constructor is currently allowed when the outer item is not generic. +// check-pass + +struct S0(usize); + +impl S0 { + fn foo() { + const C: S0 = Self(0); + fn bar() -> S0 { + Self(0) + } + } +} + +fn main() {} diff --git a/tests/ui/statics/issue-91050-1.rs b/tests/ui/statics/issue-91050-1.rs index 403a41462ef..c6268dba567 100644 --- a/tests/ui/statics/issue-91050-1.rs +++ b/tests/ui/statics/issue-91050-1.rs @@ -12,6 +12,8 @@ // // In regular builds, the bad cast was UB, like "Invalid LLVMRustVisibility value!" +#![allow(dropping_copy_types)] + pub mod before { #[no_mangle] pub static GLOBAL1: [u8; 1] = [1]; diff --git a/tests/ui/suggestions/derive-macro-missing-bounds.stderr b/tests/ui/suggestions/derive-macro-missing-bounds.stderr index c3f305c1770..bffcb1af487 100644 --- a/tests/ui/suggestions/derive-macro-missing-bounds.stderr +++ b/tests/ui/suggestions/derive-macro-missing-bounds.stderr @@ -36,7 +36,7 @@ LL | impl<T: Debug + Trait> Debug for Inner<T> { | unsatisfied trait bound introduced here = note: 1 redundant requirement hidden = note: required for `&c::Inner<T>` to implement `Debug` - = note: required for the cast from `&c::Inner<T>` to the object type `dyn Debug` + = note: required for the cast from `&&c::Inner<T>` to `&dyn Debug` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | @@ -58,7 +58,7 @@ LL | impl<T> Debug for Inner<T> where T: Debug, T: Trait { | ^^^^^ ^^^^^^^^ ----- unsatisfied trait bound introduced here = note: 1 redundant requirement hidden = note: required for `&d::Inner<T>` to implement `Debug` - = note: required for the cast from `&d::Inner<T>` to the object type `dyn Debug` + = note: required for the cast from `&&d::Inner<T>` to `&dyn Debug` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | @@ -80,7 +80,7 @@ LL | impl<T> Debug for Inner<T> where T: Debug + Trait { | ^^^^^ ^^^^^^^^ ----- unsatisfied trait bound introduced here = note: 1 redundant requirement hidden = note: required for `&e::Inner<T>` to implement `Debug` - = note: required for the cast from `&e::Inner<T>` to the object type `dyn Debug` + = note: required for the cast from `&&e::Inner<T>` to `&dyn Debug` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | @@ -102,7 +102,7 @@ LL | impl<T: Debug> Debug for Inner<T> where T: Trait { | ^^^^^ ^^^^^^^^ ----- unsatisfied trait bound introduced here = note: 1 redundant requirement hidden = note: required for `&f::Inner<T>` to implement `Debug` - = note: required for the cast from `&f::Inner<T>` to the object type `dyn Debug` + = note: required for the cast from `&&f::Inner<T>` to `&dyn Debug` = note: this error originates in the derive macro `Debug` (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | diff --git a/tests/ui/suggestions/issue-109854.rs b/tests/ui/suggestions/issue-109854.rs new file mode 100644 index 00000000000..dd4542dd71f --- /dev/null +++ b/tests/ui/suggestions/issue-109854.rs @@ -0,0 +1,12 @@ +fn generate_setter() { + String::with_capacity( + //~^ ERROR this function takes 1 argument but 3 arguments were supplied + generate_setter, + r#" +pub(crate) struct Person<T: Clone> {} +"#, + r#""#, + ); +} + +fn main() {} diff --git a/tests/ui/suggestions/issue-109854.stderr b/tests/ui/suggestions/issue-109854.stderr new file mode 100644 index 00000000000..621a3897165 --- /dev/null +++ b/tests/ui/suggestions/issue-109854.stderr @@ -0,0 +1,31 @@ +error[E0061]: this function takes 1 argument but 3 arguments were supplied + --> $DIR/issue-109854.rs:2:5 + | +LL | String::with_capacity( + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | / r#" +LL | | pub(crate) struct Person<T: Clone> {} +LL | | "#, + | |__- unexpected argument of type `&'static str` +LL | r#""#, + | ----- unexpected argument of type `&'static str` + | +note: expected `usize`, found fn item + --> $DIR/issue-109854.rs:4:5 + | +LL | generate_setter, + | ^^^^^^^^^^^^^^^ + = note: expected type `usize` + found fn item `fn() {generate_setter}` +note: associated function defined here + --> $SRC_DIR/alloc/src/string.rs:LL:COL +help: remove the extra arguments + | +LL - generate_setter, +LL + /* usize */, + | + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0061`. diff --git a/tests/ui/suggestions/issue-94171.rs b/tests/ui/suggestions/issue-94171.rs new file mode 100644 index 00000000000..cbb9f9cec72 --- /dev/null +++ b/tests/ui/suggestions/issue-94171.rs @@ -0,0 +1,5 @@ +fn L(]{match +(; {` +//~^^ ERROR mismatched closing delimiter +//~^^ ERROR unknown start of token +//~ ERROR this file contains an unclosed delimiter diff --git a/tests/ui/suggestions/issue-94171.stderr b/tests/ui/suggestions/issue-94171.stderr new file mode 100644 index 00000000000..b3440e46e8a --- /dev/null +++ b/tests/ui/suggestions/issue-94171.stderr @@ -0,0 +1,36 @@ +error: unknown start of token: ` + --> $DIR/issue-94171.rs:2:5 + | +LL | (; {` + | ^ + | +help: Unicode character '`' (Grave Accent) looks like ''' (Single Quote), but it is not + | +LL | (; {' + | ~ + +error: mismatched closing delimiter: `]` + --> $DIR/issue-94171.rs:1:5 + | +LL | fn L(]{match + | ^^ mismatched closing delimiter + | | + | unclosed delimiter + +error: this file contains an unclosed delimiter + --> $DIR/issue-94171.rs:5:52 + | +LL | fn L(]{match + | -- unclosed delimiter + | | + | missing open `[` for this delimiter +LL | (; {` + | - - unclosed delimiter + | | + | unclosed delimiter +... +LL | + | ^ + +error: aborting due to 3 previous errors + diff --git a/tests/ui/suggestions/issue-99597.rs b/tests/ui/suggestions/issue-99597.rs new file mode 100644 index 00000000000..8ba9e1fdd62 --- /dev/null +++ b/tests/ui/suggestions/issue-99597.rs @@ -0,0 +1,15 @@ +#![allow(dead_code)] + +trait T1 { } + +trait T2 { + fn test(&self) { } +} + +fn go(s: &impl T1) { + //~^ SUGGESTION ( + s.test(); + //~^ ERROR no method named `test` +} + +fn main() { } diff --git a/tests/ui/suggestions/issue-99597.stderr b/tests/ui/suggestions/issue-99597.stderr new file mode 100644 index 00000000000..bdf2a07c143 --- /dev/null +++ b/tests/ui/suggestions/issue-99597.stderr @@ -0,0 +1,15 @@ +error[E0599]: no method named `test` found for reference `&impl T1` in the current scope + --> $DIR/issue-99597.rs:11:7 + | +LL | s.test(); + | ^^^^ method not found in `&impl T1` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `test`, perhaps you need to restrict type parameter `impl T1` with it: + | +LL | fn go(s: &(impl T1 + T2)) { + | + +++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/suggestions/suggest-borrow-to-dyn-object.rs b/tests/ui/suggestions/suggest-borrow-to-dyn-object.rs deleted file mode 100644 index 120fc538307..00000000000 --- a/tests/ui/suggestions/suggest-borrow-to-dyn-object.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::ffi::{OsStr, OsString}; -use std::path::Path; - -fn check(p: &dyn AsRef<Path>) { - let m = std::fs::metadata(&p); - println!("{:?}", &m); -} - -fn main() { - let s: OsString = ".".into(); - let s: &OsStr = &s; - check(s); - //~^ ERROR the size for values of type `[u8]` cannot be known at compilation time - //~| HELP within `OsStr`, the trait `Sized` is not implemented for `[u8]` - //~| HELP consider borrowing the value, since `&OsStr` can be coerced into `dyn AsRef<Path>` -} diff --git a/tests/ui/suggestions/suggest-borrow-to-dyn-object.stderr b/tests/ui/suggestions/suggest-borrow-to-dyn-object.stderr deleted file mode 100644 index 365c1016eb3..00000000000 --- a/tests/ui/suggestions/suggest-borrow-to-dyn-object.stderr +++ /dev/null @@ -1,18 +0,0 @@ -error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/suggest-borrow-to-dyn-object.rs:12:11 - | -LL | check(s); - | ^ doesn't have a size known at compile-time - | - = help: within `OsStr`, the trait `Sized` is not implemented for `[u8]` -note: required because it appears within the type `OsStr` - --> $SRC_DIR/std/src/ffi/os_str.rs:LL:COL - = note: required for the cast from `OsStr` to the object type `dyn AsRef<Path>` -help: consider borrowing the value, since `&OsStr` can be coerced into `dyn AsRef<Path>` - | -LL | check(&s); - | + - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/track-diagnostics/track6.rs b/tests/ui/track-diagnostics/track6.rs index 307e3101849..fc6f5f23d92 100644 --- a/tests/ui/track-diagnostics/track6.rs +++ b/tests/ui/track-diagnostics/track6.rs @@ -1,6 +1,9 @@ // compile-flags: -Z track-diagnostics // error-pattern: created at +// Normalize the emitted location so this doesn't need +// updating everytime someone adds or removes a line. +// normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC" pub trait Foo { diff --git a/tests/ui/track-diagnostics/track6.stderr b/tests/ui/track-diagnostics/track6.stderr index 1c7537633ff..89438aea9ad 100644 --- a/tests/ui/track-diagnostics/track6.stderr +++ b/tests/ui/track-diagnostics/track6.stderr @@ -1,9 +1,9 @@ error[E0658]: specialization is unstable - --> $DIR/track6.rs:11:5 + --> $DIR/track6.rs:LL:CC | LL | default fn bar() {} | ^^^^^^^^^^^^^^^^^^^ --Ztrack-diagnostics: created at $COMPILER_DIR/rustc_session/src/parse.rs:93:5 +-Ztrack-diagnostics: created at $COMPILER_DIR/rustc_session/src/parse.rs:LL:CC | = note: see issue #31844 <https://github.com/rust-lang/rust/issues/31844> for more information = help: add `#![feature(specialization)]` to the crate attributes to enable diff --git a/tests/ui/traits/coercion-generic-bad.stderr b/tests/ui/traits/coercion-generic-bad.stderr index 93d6770eb47..e7e8a796796 100644 --- a/tests/ui/traits/coercion-generic-bad.stderr +++ b/tests/ui/traits/coercion-generic-bad.stderr @@ -5,7 +5,7 @@ LL | let s: Box<dyn Trait<isize>> = Box::new(Struct { person: "Fred" }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait<isize>` is not implemented for `Struct` | = help: the trait `Trait<&'static str>` is implemented for `Struct` - = note: required for the cast from `Struct` to the object type `dyn Trait<isize>` + = note: required for the cast from `Box<Struct>` to `Box<dyn Trait<isize>>` error: aborting due to previous error diff --git a/tests/ui/traits/copy-guessing.rs b/tests/ui/traits/copy-guessing.rs index f031dd9ca48..af25010e3bd 100644 --- a/tests/ui/traits/copy-guessing.rs +++ b/tests/ui/traits/copy-guessing.rs @@ -1,5 +1,6 @@ -// run-pass #![allow(dead_code)] +#![allow(dropping_copy_types)] + // "guessing" in trait selection can affect `copy_or_move`. Check that this // is correctly handled. I am not sure what is the "correct" behaviour, // but we should at least not ICE. @@ -17,6 +18,7 @@ fn assert_impls_fn<R,T: Fn()->R>(_: &T){} fn main() { let n = None; + //~^ ERROR type annotations needed for `Option<T>` let e = S(&n); let f = || { // S being copy is critical for this to work diff --git a/tests/ui/traits/copy-guessing.stderr b/tests/ui/traits/copy-guessing.stderr new file mode 100644 index 00000000000..568b7e5a64a --- /dev/null +++ b/tests/ui/traits/copy-guessing.stderr @@ -0,0 +1,14 @@ +error[E0282]: type annotations needed for `Option<T>` + --> $DIR/copy-guessing.rs:20:9 + | +LL | let n = None; + | ^ + | +help: consider giving `n` an explicit type, where the type for type parameter `T` is specified + | +LL | let n: Option<T> = None; + | +++++++++++ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/tests/ui/traits/cycle-cache-err-60010.stderr b/tests/ui/traits/cycle-cache-err-60010.stderr index 2ff16b4af38..aee41c43aef 100644 --- a/tests/ui/traits/cycle-cache-err-60010.stderr +++ b/tests/ui/traits/cycle-cache-err-60010.stderr @@ -1,9 +1,25 @@ -error[E0275]: overflow evaluating the requirement `RootDatabase: RefUnwindSafe` +error[E0275]: overflow evaluating the requirement `SalsaStorage: RefUnwindSafe` --> $DIR/cycle-cache-err-60010.rs:27:13 | LL | _parse: <ParseQuery as Query<RootDatabase>>::Data, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: required because it appears within the type `PhantomData<SalsaStorage>` + --> $SRC_DIR/core/src/marker.rs:LL:COL +note: required because it appears within the type `Unique<SalsaStorage>` + --> $SRC_DIR/core/src/ptr/unique.rs:LL:COL +note: required because it appears within the type `Box<SalsaStorage>` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL +note: required because it appears within the type `Runtime<RootDatabase>` + --> $DIR/cycle-cache-err-60010.rs:23:8 + | +LL | struct Runtime<DB: Database> { + | ^^^^^^^ +note: required because it appears within the type `RootDatabase` + --> $DIR/cycle-cache-err-60010.rs:20:8 + | +LL | struct RootDatabase { + | ^^^^^^^^^^^^ note: required for `RootDatabase` to implement `SourceDatabase` --> $DIR/cycle-cache-err-60010.rs:44:9 | diff --git a/tests/ui/traits/impl-evaluation-order.rs b/tests/ui/traits/impl-evaluation-order.rs index 57809d89aa6..2ce0b6b0df8 100644 --- a/tests/ui/traits/impl-evaluation-order.rs +++ b/tests/ui/traits/impl-evaluation-order.rs @@ -6,6 +6,8 @@ // check-pass +#![allow(dropping_copy_types)] + trait A { type B; } diff --git a/tests/ui/traits/issue-106072.rs b/tests/ui/traits/issue-106072.rs index 7064a39d21e..b174669545a 100644 --- a/tests/ui/traits/issue-106072.rs +++ b/tests/ui/traits/issue-106072.rs @@ -1,5 +1,4 @@ #[derive(Clone)] //~ trait objects must include the `dyn` keyword - //~| trait objects must include the `dyn` keyword struct Foo; trait Foo {} //~ the name `Foo` is defined multiple times fn main() {} diff --git a/tests/ui/traits/issue-106072.stderr b/tests/ui/traits/issue-106072.stderr index f9b7b814663..1037603ceb7 100644 --- a/tests/ui/traits/issue-106072.stderr +++ b/tests/ui/traits/issue-106072.stderr @@ -1,5 +1,5 @@ error[E0428]: the name `Foo` is defined multiple times - --> $DIR/issue-106072.rs:4:1 + --> $DIR/issue-106072.rs:3:1 | LL | struct Foo; | ----------- previous definition of the type `Foo` here @@ -16,15 +16,7 @@ LL | #[derive(Clone)] | = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0782]: trait objects must include the `dyn` keyword - --> $DIR/issue-106072.rs:1:10 - | -LL | #[derive(Clone)] - | ^^^^^ - | - = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0428, E0782. For more information about an error, try `rustc --explain E0428`. diff --git a/tests/ui/traits/issue-20692.stderr b/tests/ui/traits/issue-20692.stderr index 2028994cdaa..30e3c9da1a0 100644 --- a/tests/ui/traits/issue-20692.stderr +++ b/tests/ui/traits/issue-20692.stderr @@ -27,8 +27,7 @@ LL | trait Array: Sized + Copy {} | | | | | ...because it requires `Self: Sized` | this trait cannot be made into an object... - = note: required for `&T` to implement `CoerceUnsized<&dyn Array>` - = note: required by cast to type `&dyn Array` + = note: required for the cast from `&T` to `&dyn Array` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/issue-38604.stderr b/tests/ui/traits/issue-38604.stderr index 50d6fb05465..d5327602430 100644 --- a/tests/ui/traits/issue-38604.stderr +++ b/tests/ui/traits/issue-38604.stderr @@ -25,8 +25,7 @@ LL | trait Foo where u32: Q<Self> { | --- ^^^^^^^ ...because it uses `Self` as a type parameter | | | this trait cannot be made into an object... - = note: required for `Box<()>` to implement `CoerceUnsized<Box<dyn Foo>>` - = note: required by cast to type `Box<dyn Foo>` + = note: required for the cast from `Box<()>` to `Box<dyn Foo>` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/issue-7013.stderr b/tests/ui/traits/issue-7013.stderr index 9ac5c4725ab..1c0e8bcf185 100644 --- a/tests/ui/traits/issue-7013.stderr +++ b/tests/ui/traits/issue-7013.stderr @@ -12,7 +12,7 @@ note: required because it appears within the type `B` | LL | struct B { | ^ - = note: required for the cast from `B` to the object type `dyn Foo + Send` + = note: required for the cast from `Box<B>` to `Box<dyn Foo + Send>` error: aborting due to previous error diff --git a/tests/ui/traits/map-types.stderr b/tests/ui/traits/map-types.stderr index f685c50b07d..4315056f206 100644 --- a/tests/ui/traits/map-types.stderr +++ b/tests/ui/traits/map-types.stderr @@ -5,7 +5,7 @@ LL | let y: Box<dyn Map<usize, isize>> = Box::new(x); | ^^^^^^^^^^^ the trait `Map<usize, isize>` is not implemented for `Box<dyn Map<isize, isize>>` | = help: the trait `Map<K, V>` is implemented for `HashMap<K, V>` - = note: required for the cast from `Box<dyn Map<isize, isize>>` to the object type `dyn Map<usize, isize>` + = note: required for the cast from `Box<Box<dyn Map<isize, isize>>>` to `Box<dyn Map<usize, isize>>` error: aborting due to previous error diff --git a/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.fail.stderr b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.fail.stderr index 6a926534e07..4aefdd6bb07 100644 --- a/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.fail.stderr +++ b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.fail.stderr @@ -1,5 +1,5 @@ error[E0277]: `impl Future<Output = ()>` cannot be sent between threads safely - --> $DIR/auto-with-drop_tracking_mir.rs:24:13 + --> $DIR/auto-with-drop_tracking_mir.rs:25:13 | LL | is_send(foo()); | ------- ^^^^^ `impl Future<Output = ()>` cannot be sent between threads safely @@ -8,7 +8,7 @@ LL | is_send(foo()); | = help: the trait `Send` is not implemented for `impl Future<Output = ()>` note: required by a bound in `is_send` - --> $DIR/auto-with-drop_tracking_mir.rs:23:24 + --> $DIR/auto-with-drop_tracking_mir.rs:24:24 | LL | fn is_send(_: impl Send) {} | ^^^^ required by this bound in `is_send` diff --git a/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs index a5db7c4636b..e311a4af2f4 100644 --- a/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs +++ b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs @@ -14,6 +14,7 @@ async fn foo() { #[cfg(fail)] let x = &NotSync; bar().await; + #[allow(dropping_references)] drop(x); } diff --git a/tests/ui/traits/new-solver/normalize-rcvr-for-inherent.rs b/tests/ui/traits/new-solver/normalize-rcvr-for-inherent.rs new file mode 100644 index 00000000000..d70534feb07 --- /dev/null +++ b/tests/ui/traits/new-solver/normalize-rcvr-for-inherent.rs @@ -0,0 +1,25 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +// Verify that we can assemble inherent impl candidates on a possibly +// unnormalized self type. + +trait Foo { + type Assoc; +} +impl Foo for i32 { + type Assoc = Bar; +} + +struct Bar; +impl Bar { + fn method(&self) {} +} + +fn build<T: Foo>(_: T) -> T::Assoc { + todo!() +} + +fn main() { + build(1i32).method(); +} diff --git a/tests/ui/traits/new-solver/structural-resolve-field.rs b/tests/ui/traits/new-solver/structural-resolve-field.rs new file mode 100644 index 00000000000..01899c9ad64 --- /dev/null +++ b/tests/ui/traits/new-solver/structural-resolve-field.rs @@ -0,0 +1,13 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +#[derive(Default)] +struct Foo { + x: i32, +} + +fn main() { + let mut xs = <[Foo; 1]>::default(); + xs[0].x = 1; + (&mut xs[0]).x = 2; +} diff --git a/tests/ui/traits/new-solver/temporary-ambiguity.rs b/tests/ui/traits/new-solver/temporary-ambiguity.rs index 18ee0545700..c6c11a1a1de 100644 --- a/tests/ui/traits/new-solver/temporary-ambiguity.rs +++ b/tests/ui/traits/new-solver/temporary-ambiguity.rs @@ -18,5 +18,5 @@ fn main() { let w = Wrapper(x); needs_foo(w); x = 1; - drop(x); + let _ = x; } diff --git a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr index 47fa29b6648..d56519223f4 100644 --- a/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr +++ b/tests/ui/traits/non_lifetime_binders/supertrait-object-safety.stderr @@ -20,8 +20,7 @@ LL | trait Foo: for<T> Bar<T> {} | --- ^^^^^^^^^^^^^ ...because where clause cannot reference non-lifetime `for<...>` variables | | | this trait cannot be made into an object... - = note: required for `&()` to implement `CoerceUnsized<&dyn Foo>` - = note: required by cast to type `&dyn Foo` + = note: required for the cast from `&()` to `&dyn Foo` error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/supertrait-object-safety.rs:19:12 diff --git a/tests/ui/traits/non_lifetime_binders/universe-error1.rs b/tests/ui/traits/non_lifetime_binders/universe-error1.rs new file mode 100644 index 00000000000..eadee6b711e --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/universe-error1.rs @@ -0,0 +1,18 @@ +#![feature(non_lifetime_binders)] +//~^ WARN the feature `non_lifetime_binders` is incomplete + +trait Other<U: ?Sized> {} + +impl<U: ?Sized> Other<U> for U {} + +#[rustfmt::skip] +fn foo<U: ?Sized>() +where + for<T> T: Other<U> {} + +fn bar() { + foo::<_>(); + //~^ ERROR the trait bound `T: Other<_>` is not satisfied +} + +fn main() {} diff --git a/tests/ui/traits/non_lifetime_binders/universe-error1.stderr b/tests/ui/traits/non_lifetime_binders/universe-error1.stderr new file mode 100644 index 00000000000..bfcad72e352 --- /dev/null +++ b/tests/ui/traits/non_lifetime_binders/universe-error1.stderr @@ -0,0 +1,27 @@ +warning: the feature `non_lifetime_binders` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/universe-error1.rs:1:12 + | +LL | #![feature(non_lifetime_binders)] + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #108185 <https://github.com/rust-lang/rust/issues/108185> for more information + = note: `#[warn(incomplete_features)]` on by default + +error[E0277]: the trait bound `T: Other<_>` is not satisfied + --> $DIR/universe-error1.rs:14:11 + | +LL | foo::<_>(); + | ^ the trait `Other<_>` is not implemented for `T` + | +note: required by a bound in `foo` + --> $DIR/universe-error1.rs:11:15 + | +LL | fn foo<U: ?Sized>() + | --- required by a bound in this function +LL | where +LL | for<T> T: Other<U> {} + | ^^^^^^^^ required by this bound in `foo` + +error: aborting due to previous error; 1 warning emitted + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/object/safety.stderr b/tests/ui/traits/object/safety.stderr index dc18adeafc7..a51b6975938 100644 --- a/tests/ui/traits/object/safety.stderr +++ b/tests/ui/traits/object/safety.stderr @@ -11,8 +11,7 @@ LL | trait Tr { | -- this trait cannot be made into an object... LL | fn foo(); | ^^^ ...because associated function `foo` has no `self` parameter - = note: required for `&St` to implement `CoerceUnsized<&dyn Tr>` - = note: required by cast to type `&dyn Tr` + = note: required for the cast from `&St` to `&dyn Tr` help: consider turning `foo` into a method by giving it a `&self` argument | LL | fn foo(&self); diff --git a/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.rs b/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.rs new file mode 100644 index 00000000000..d37943b929a --- /dev/null +++ b/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.rs @@ -0,0 +1,34 @@ +//~ ERROR overflow +// A regression test for #111729 checking that we correctly +// track recursion depth for obligations returned by confirmation. +use std::panic::RefUnwindSafe; + +trait Database { + type Storage; +} +trait Query<DB> { + type Data; +} +struct ParseQuery; +struct RootDatabase { + _runtime: Runtime<RootDatabase>, +} + +impl<T: RefUnwindSafe> Database for T { + type Storage = SalsaStorage; +} +impl Database for RootDatabase { + type Storage = SalsaStorage; +} + +struct Runtime<DB: Database> { + _storage: Box<DB::Storage>, +} +struct SalsaStorage { + _parse: <ParseQuery as Query<RootDatabase>>::Data, +} + +impl<DB: Database> Query<DB> for ParseQuery { + type Data = RootDatabase; +} +fn main() {} diff --git a/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.stderr b/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.stderr new file mode 100644 index 00000000000..8f9ce3ef1e9 --- /dev/null +++ b/tests/ui/traits/solver-cycles/cycle-via-builtin-auto-trait-impl.stderr @@ -0,0 +1,24 @@ +error[E0275]: overflow evaluating the requirement `Runtime<RootDatabase>: RefUnwindSafe` + | + = help: consider increasing the recursion limit by adding a `#![recursion_limit = "256"]` attribute to your crate (`cycle_via_builtin_auto_trait_impl`) +note: required because it appears within the type `RootDatabase` + --> $DIR/cycle-via-builtin-auto-trait-impl.rs:13:8 + | +LL | struct RootDatabase { + | ^^^^^^^^^^^^ +note: required for `RootDatabase` to implement `Database` + --> $DIR/cycle-via-builtin-auto-trait-impl.rs:17:24 + | +LL | impl<T: RefUnwindSafe> Database for T { + | ------------- ^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +note: required because it appears within the type `Runtime<RootDatabase>` + --> $DIR/cycle-via-builtin-auto-trait-impl.rs:24:8 + | +LL | struct Runtime<DB: Database> { + | ^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/test-2.stderr b/tests/ui/traits/test-2.stderr index 6c0e8b8af4b..74a0fc42708 100644 --- a/tests/ui/traits/test-2.stderr +++ b/tests/ui/traits/test-2.stderr @@ -76,8 +76,7 @@ LL | trait bar { fn dup(&self) -> Self; fn blah<X>(&self); } | this trait cannot be made into an object... = help: consider moving `dup` to another trait = help: consider moving `blah` to another trait - = note: required for `Box<{integer}>` to implement `CoerceUnsized<Box<dyn bar>>` - = note: required by cast to type `Box<dyn bar>` + = note: required for the cast from `Box<{integer}>` to `Box<dyn bar>` error: aborting due to 5 previous errors diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-1.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-1.stderr index fe269d8e99b..82b4e9bd72a 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-1.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-1.stderr @@ -15,7 +15,7 @@ error[E0277]: the trait bound `&dyn Foo: Bar<_>` is not satisfied LL | let _ = x as &dyn Bar<_>; // Ambiguous | ^ the trait `Bar<_>` is not implemented for `&dyn Foo` | - = note: required for the cast from `&dyn Foo` to the object type `dyn Bar<_>` + = note: required for the cast from `&&dyn Foo` to `&dyn Bar<_>` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr b/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr index ef007d5cb90..856303ef4dd 100644 --- a/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr +++ b/tests/ui/traits/trait-upcasting/type-checking-test-2.stderr @@ -15,7 +15,7 @@ error[E0277]: the trait bound `&dyn Foo<i32>: Bar<u32>` is not satisfied LL | let _ = x as &dyn Bar<u32>; // Error | ^ the trait `Bar<u32>` is not implemented for `&dyn Foo<i32>` | - = note: required for the cast from `&dyn Foo<i32>` to the object type `dyn Bar<u32>` + = note: required for the cast from `&&dyn Foo<i32>` to `&dyn Bar<u32>` error[E0605]: non-primitive cast: `&dyn Foo<u32>` as `&dyn Bar<_>` --> $DIR/type-checking-test-2.rs:25:13 @@ -34,7 +34,7 @@ error[E0277]: the trait bound `&dyn Foo<u32>: Bar<_>` is not satisfied LL | let a = x as &dyn Bar<_>; // Ambiguous | ^ the trait `Bar<_>` is not implemented for `&dyn Foo<u32>` | - = note: required for the cast from `&dyn Foo<u32>` to the object type `dyn Bar<_>` + = note: required for the cast from `&&dyn Foo<u32>` to `&dyn Bar<_>` error: aborting due to 4 previous errors diff --git a/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy.rs b/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy.rs index 3416503b851..f98c3164d7e 100644 --- a/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy.rs +++ b/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy.rs @@ -1,6 +1,8 @@ // check-pass // Check tautalogically false `Copy` bounds + #![feature(trivial_bounds)] +#![allow(dropping_references, dropping_copy_types)] fn copy_string(t: String) -> String where String: Copy { //~ WARNING trivial_bounds is_copy(&t); diff --git a/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr b/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr index 1e26623899b..deeb352a2a8 100644 --- a/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr +++ b/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr @@ -1,5 +1,5 @@ warning: trait bound String: Copy does not depend on any type or lifetime parameters - --> $DIR/trivial-bounds-inconsistent-copy.rs:5:51 + --> $DIR/trivial-bounds-inconsistent-copy.rs:7:51 | LL | fn copy_string(t: String) -> String where String: Copy { | ^^^^ @@ -7,19 +7,19 @@ LL | fn copy_string(t: String) -> String where String: Copy { = note: `#[warn(trivial_bounds)]` on by default warning: trait bound String: Copy does not depend on any type or lifetime parameters - --> $DIR/trivial-bounds-inconsistent-copy.rs:12:56 + --> $DIR/trivial-bounds-inconsistent-copy.rs:14:56 | LL | fn copy_out_string(t: &String) -> String where String: Copy { | ^^^^ warning: trait bound String: Copy does not depend on any type or lifetime parameters - --> $DIR/trivial-bounds-inconsistent-copy.rs:16:55 + --> $DIR/trivial-bounds-inconsistent-copy.rs:18:55 | LL | fn copy_string_with_param<T>(x: String) where String: Copy { | ^^^^ warning: trait bound for<'b> &'b mut i32: Copy does not depend on any type or lifetime parameters - --> $DIR/trivial-bounds-inconsistent-copy.rs:22:76 + --> $DIR/trivial-bounds-inconsistent-copy.rs:24:76 | LL | fn copy_mut<'a>(t: &&'a mut i32) -> &'a mut i32 where for<'b> &'b mut i32: Copy { | ^^^^ diff --git a/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs b/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs index 551815d021a..58eaa9c2c42 100644 --- a/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs +++ b/tests/ui/type-alias-impl-trait/associated-type-impl-trait-lifetime.rs @@ -5,15 +5,16 @@ trait Trait { type Opaque1; type Opaque2; - fn constrain(self); + fn constrain(self) -> (Self::Opaque1, Self::Opaque2); } impl<'a> Trait for &'a () { type Opaque1 = impl Sized; type Opaque2 = impl Sized + 'a; - fn constrain(self) { - let _: Self::Opaque1 = (); - let _: Self::Opaque2 = self; + fn constrain(self) -> (Self::Opaque1, Self::Opaque2) { + let a: Self::Opaque1 = (); + let b: Self::Opaque2 = self; + (a, b) } } diff --git a/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.rs b/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.rs new file mode 100644 index 00000000000..93c52126d69 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.rs @@ -0,0 +1,16 @@ +#![feature(impl_trait_in_assoc_type)] + +trait Foo { + type Foo; + fn bar(); +} + +impl Foo for () { + type Foo = impl std::fmt::Debug; + fn bar() { + let x: Self::Foo = (); + //~^ ERROR: mismatched types + } +} + +fn main() {} diff --git a/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr b/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr new file mode 100644 index 00000000000..2beed73cb85 --- /dev/null +++ b/tests/ui/type-alias-impl-trait/invalid_impl_trait_in_assoc_ty.stderr @@ -0,0 +1,22 @@ +error[E0308]: mismatched types + --> $DIR/invalid_impl_trait_in_assoc_ty.rs:11:28 + | +LL | type Foo = impl std::fmt::Debug; + | -------------------- the expected opaque type +LL | fn bar() { +LL | let x: Self::Foo = (); + | --------- ^^ expected opaque type, found `()` + | | + | expected due to this + | + = note: expected opaque type `<() as Foo>::Foo` + found unit type `()` +note: this item must have the opaque type in its signature in order to be able to register hidden types + --> $DIR/invalid_impl_trait_in_assoc_ty.rs:10:5 + | +LL | fn bar() { + | ^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/type-alias-impl-trait/issue-98604.stderr b/tests/ui/type-alias-impl-trait/issue-98604.stderr index fa16d321890..af758d8099f 100644 --- a/tests/ui/type-alias-impl-trait/issue-98604.stderr +++ b/tests/ui/type-alias-impl-trait/issue-98604.stderr @@ -4,7 +4,7 @@ error[E0271]: expected `test` to be a fn item that returns `Pin<Box<dyn Future<O LL | Box::new(test) as AsyncFnPtr; | ^^^^^^^^^^^^^^ expected `Pin<Box<dyn Future<Output = ()>>>`, found future | - = note: required for the cast from `fn() -> impl Future<Output = ()> {test}` to the object type `dyn Fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>>` + = note: required for the cast from `Box<fn() -> impl Future<Output = ()> {test}>` to `Box<(dyn Fn() -> Pin<Box<(dyn Future<Output = ()> + 'static)>> + 'static)>` error: aborting due to previous error diff --git a/tests/ui/type-alias-impl-trait/issue-98608.stderr b/tests/ui/type-alias-impl-trait/issue-98608.stderr index 506d40cb776..9b651008371 100644 --- a/tests/ui/type-alias-impl-trait/issue-98608.stderr +++ b/tests/ui/type-alias-impl-trait/issue-98608.stderr @@ -9,7 +9,7 @@ LL | let b: Box<dyn Fn() -> Box<u8>> = Box::new(hi); | = note: expected struct `Box<u8>` found opaque type `impl Sized` - = note: required for the cast from `fn() -> impl Sized {hi}` to the object type `dyn Fn() -> Box<u8>` + = note: required for the cast from `Box<fn() -> impl Sized {hi}>` to `Box<dyn Fn() -> Box<u8>>` error: aborting due to previous error diff --git a/tests/ui/type/issue-58355.stderr b/tests/ui/type/issue-58355.stderr index 6f89a7b0049..67078bcfe89 100644 --- a/tests/ui/type/issue-58355.stderr +++ b/tests/ui/type/issue-58355.stderr @@ -6,7 +6,7 @@ LL | x = Some(Box::new(callback)); | = help: within `fn() -> dyn ToString`, the trait `Sized` is not implemented for `dyn ToString` = note: required because it appears within the type `fn() -> dyn ToString` - = note: required for the cast from `fn() -> dyn ToString` to the object type `dyn Fn() -> (dyn ToString + 'static)` + = note: required for the cast from `Box<fn() -> dyn ToString>` to `Box<dyn Fn() -> (dyn ToString + 'static)>` error: aborting due to previous error diff --git a/tests/ui/type/type-dependent-def-issue-49241.rs b/tests/ui/type/type-dependent-def-issue-49241.rs index caf5bade5c7..4b6bc6124db 100644 --- a/tests/ui/type/type-dependent-def-issue-49241.rs +++ b/tests/ui/type/type-dependent-def-issue-49241.rs @@ -2,5 +2,4 @@ fn main() { let v = vec![0]; const l: usize = v.count(); //~ ERROR attempt to use a non-constant value in a constant let s: [u32; l] = v.into_iter().collect(); - //~^ constant } diff --git a/tests/ui/type/type-dependent-def-issue-49241.stderr b/tests/ui/type/type-dependent-def-issue-49241.stderr index af16a6e8f84..64c7687f7a8 100644 --- a/tests/ui/type/type-dependent-def-issue-49241.stderr +++ b/tests/ui/type/type-dependent-def-issue-49241.stderr @@ -6,12 +6,6 @@ LL | const l: usize = v.count(); | | | help: consider using `let` instead of `const`: `let l` -note: erroneous constant used - --> $DIR/type-dependent-def-issue-49241.rs:4:18 - | -LL | let s: [u32; l] = v.into_iter().collect(); - | ^ - error: aborting due to previous error For more information about this error, try `rustc --explain E0435`. diff --git a/tests/ui/type/type-path-err-node-types.stderr b/tests/ui/type/type-path-err-node-types.stderr index 1aed1dbe4ba..8b12aa1a393 100644 --- a/tests/ui/type/type-path-err-node-types.stderr +++ b/tests/ui/type/type-path-err-node-types.stderr @@ -1,9 +1,3 @@ -error[E0433]: failed to resolve: use of undeclared type `NonExistent` - --> $DIR/type-path-err-node-types.rs:15:5 - | -LL | NonExistent::Assoc::<u8>; - | ^^^^^^^^^^^ use of undeclared type `NonExistent` - error[E0412]: cannot find type `Nonexistent` in this scope --> $DIR/type-path-err-node-types.rs:7:12 | @@ -22,6 +16,12 @@ error[E0425]: cannot find value `nonexistent` in this scope LL | nonexistent.nonexistent::<u8>(); | ^^^^^^^^^^^ not found in this scope +error[E0433]: failed to resolve: use of undeclared type `NonExistent` + --> $DIR/type-path-err-node-types.rs:15:5 + | +LL | NonExistent::Assoc::<u8>; + | ^^^^^^^^^^^ use of undeclared type `NonExistent` + error[E0282]: type annotations needed --> $DIR/type-path-err-node-types.rs:23:14 | diff --git a/tests/ui/underscore-imports/issue-110164.rs b/tests/ui/underscore-imports/issue-110164.rs new file mode 100644 index 00000000000..6fd13414500 --- /dev/null +++ b/tests/ui/underscore-imports/issue-110164.rs @@ -0,0 +1,19 @@ +use self::*; +//~^ ERROR unresolved import `self::*` +use crate::*; +//~^ ERROR unresolved import `crate::*` +use _::a; +//~^ ERROR expected identifier, found reserved identifier `_` +//~| ERROR unresolved import `_` +use _::*; +//~^ ERROR expected identifier, found reserved identifier `_` +//~| ERROR unresolved import `_` + +fn main() { + use _::a; + //~^ ERROR expected identifier, found reserved identifier `_` + //~| ERROR unresolved import `_` + use _::*; + //~^ ERROR expected identifier, found reserved identifier `_` + //~| ERROR unresolved import `_` +} diff --git a/tests/ui/underscore-imports/issue-110164.stderr b/tests/ui/underscore-imports/issue-110164.stderr new file mode 100644 index 00000000000..5016c41e8a5 --- /dev/null +++ b/tests/ui/underscore-imports/issue-110164.stderr @@ -0,0 +1,71 @@ +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-110164.rs:5:5 + | +LL | use _::a; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-110164.rs:8:5 + | +LL | use _::*; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-110164.rs:13:9 + | +LL | use _::a; + | ^ expected identifier, found reserved identifier + +error: expected identifier, found reserved identifier `_` + --> $DIR/issue-110164.rs:16:9 + | +LL | use _::*; + | ^ expected identifier, found reserved identifier + +error[E0432]: unresolved import `self::*` + --> $DIR/issue-110164.rs:1:5 + | +LL | use self::*; + | ^^^^^^^ cannot glob-import a module into itself + +error[E0432]: unresolved import `crate::*` + --> $DIR/issue-110164.rs:3:5 + | +LL | use crate::*; + | ^^^^^^^^ cannot glob-import a module into itself + +error[E0432]: unresolved import `_` + --> $DIR/issue-110164.rs:8:5 + | +LL | use _::*; + | ^ maybe a missing crate `_`? + | + = help: consider adding `extern crate _` to use the `_` crate + +error[E0432]: unresolved import `_` + --> $DIR/issue-110164.rs:5:5 + | +LL | use _::a; + | ^ maybe a missing crate `_`? + | + = help: consider adding `extern crate _` to use the `_` crate + +error[E0432]: unresolved import `_` + --> $DIR/issue-110164.rs:13:9 + | +LL | use _::a; + | ^ maybe a missing crate `_`? + | + = help: consider adding `extern crate _` to use the `_` crate + +error[E0432]: unresolved import `_` + --> $DIR/issue-110164.rs:16:9 + | +LL | use _::*; + | ^ maybe a missing crate `_`? + | + = help: consider adding `extern crate _` to use the `_` crate + +error: aborting due to 10 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/unsized-locals/align.rs b/tests/ui/unsized-locals/align.rs new file mode 100644 index 00000000000..01be8f3bb9c --- /dev/null +++ b/tests/ui/unsized-locals/align.rs @@ -0,0 +1,30 @@ +// Test that unsized locals uphold alignment requirements. +// Regression test for #71416. +// run-pass +#![feature(unsized_locals)] +#![allow(incomplete_features)] +use std::any::Any; + +#[repr(align(256))] +#[allow(dead_code)] +struct A { + v: u8 +} + +impl A { + fn f(&self) -> *const A { + assert_eq!(self as *const A as usize % 256, 0); + self + } +} + +fn mk() -> Box<dyn Any> { + Box::new(A { v: 4 }) +} + +fn main() { + let x = *mk(); + let dwncst = x.downcast_ref::<A>().unwrap(); + let addr = dwncst.f(); + assert_eq!(addr as usize % 256, 0); +} diff --git a/tests/ui/unsized/unsized-fn-param.stderr b/tests/ui/unsized/unsized-fn-param.stderr index b4772605432..0de3dbbb557 100644 --- a/tests/ui/unsized/unsized-fn-param.stderr +++ b/tests/ui/unsized/unsized-fn-param.stderr @@ -5,8 +5,8 @@ LL | foo11("bar", &"baz"); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast from `str` to the object type `dyn AsRef<Path>` -help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<Path>` + = note: required for the cast from `&'static str` to `&dyn AsRef<Path>` +help: consider borrowing the value, since `&&'static str` can be coerced into `&dyn AsRef<Path>` | LL | foo11(&"bar", &"baz"); | + @@ -18,8 +18,8 @@ LL | foo12(&"bar", "baz"); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast from `str` to the object type `dyn AsRef<Path>` -help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<Path>` + = note: required for the cast from `&'static str` to `&dyn AsRef<Path>` +help: consider borrowing the value, since `&&'static str` can be coerced into `&dyn AsRef<Path>` | LL | foo12(&"bar", &"baz"); | + @@ -31,8 +31,8 @@ LL | foo21("bar", &"baz"); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast from `str` to the object type `dyn AsRef<str>` -help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<str>` + = note: required for the cast from `&'static str` to `&dyn AsRef<str>` +help: consider borrowing the value, since `&&'static str` can be coerced into `&dyn AsRef<str>` | LL | foo21(&"bar", &"baz"); | + @@ -44,8 +44,8 @@ LL | foo22(&"bar", "baz"); | ^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `str` - = note: required for the cast from `str` to the object type `dyn AsRef<str>` -help: consider borrowing the value, since `&str` can be coerced into `dyn AsRef<str>` + = note: required for the cast from `&'static str` to `&dyn AsRef<str>` +help: consider borrowing the value, since `&&'static str` can be coerced into `&dyn AsRef<str>` | LL | foo22(&"bar", &"baz"); | + diff --git a/tests/ui/use/use-self-type.stderr b/tests/ui/use/use-self-type.stderr index e6153941151..3da04a851f6 100644 --- a/tests/ui/use/use-self-type.stderr +++ b/tests/ui/use/use-self-type.stderr @@ -8,7 +8,7 @@ error[E0432]: unresolved import `Self` --> $DIR/use-self-type.rs:6:13 | LL | use Self::f; - | ^^^^ `Self` is only available in impls, traits, and type definitions + | ^^^^ `Self` cannot be used in imports error: aborting due to 2 previous errors diff --git a/tests/ui/weird-exprs.rs b/tests/ui/weird-exprs.rs index d65703ef5ca..c4fa850a4f9 100644 --- a/tests/ui/weird-exprs.rs +++ b/tests/ui/weird-exprs.rs @@ -5,13 +5,16 @@ #![allow(non_camel_case_types)] #![allow(dead_code)] +#![allow(redundant_semicolons)] #![allow(unreachable_code)] #![allow(unused_braces, unused_must_use, unused_parens)] #![allow(uncommon_codepoints, confusable_idents)] +#![allow(unused_imports)] #![allow(unreachable_patterns)] #![recursion_limit = "256"] +extern crate core; use std::cell::Cell; use std::mem::swap; @@ -204,6 +207,30 @@ fn closure_matching() { assert!(matches!(x(..), |_| Some(4))); } +fn semisemisemisemisemi() { + ;;;;;;; ;;;;;;; ;;; ;;; ;; + ;; ;; ;;;; ;;;; ;; + ;;;;;;; ;;;;; ;; ;;;; ;; ;; + ;; ;; ;; ;; ;; ;; + ;;;;;;; ;;;;;;; ;; ;; ;; +} + +fn useful_syntax() { + use {{std::{{collections::{{HashMap}}}}}}; + use ::{{{{core}, {std}}}}; + use {{::{{core as core2}}}}; +} + +fn infcx() { + pub mod cx { + pub mod cx { + pub use super::cx; + pub struct Cx; + } + } + let _cx: cx::cx::Cx = cx::cx::cx::cx::cx::Cx; +} + pub fn main() { strange(); funny(); @@ -227,4 +254,7 @@ pub fn main() { function(); bathroom_stall(); closure_matching(); + semisemisemisemisemi(); + useful_syntax(); + infcx(); } diff --git a/tests/ui/wf/wf-convert-unsafe-trait-obj-box.stderr b/tests/ui/wf/wf-convert-unsafe-trait-obj-box.stderr index 6cf4f33f947..40a25c7df6b 100644 --- a/tests/ui/wf/wf-convert-unsafe-trait-obj-box.stderr +++ b/tests/ui/wf/wf-convert-unsafe-trait-obj-box.stderr @@ -11,8 +11,7 @@ LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | | this trait cannot be made into an object... - = note: required for `Box<S>` to implement `CoerceUnsized<Box<dyn Trait>>` - = note: required by cast to type `Box<dyn Trait>` + = note: required for the cast from `Box<S>` to `Box<dyn Trait>` error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-convert-unsafe-trait-obj-box.rs:17:15 @@ -27,8 +26,7 @@ LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | | this trait cannot be made into an object... - = note: required for `Box<S>` to implement `CoerceUnsized<Box<dyn Trait>>` - = note: required by cast to type `Box<(dyn Trait + 'static)>` + = note: required for the cast from `Box<S>` to `Box<(dyn Trait + 'static)>` error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-convert-unsafe-trait-obj-box.rs:15:5 @@ -43,8 +41,7 @@ LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | | this trait cannot be made into an object... - = note: required for `Box<S>` to implement `CoerceUnsized<Box<dyn Trait>>` - = note: required by cast to type `Box<dyn Trait>` + = note: required for the cast from `Box<S>` to `Box<dyn Trait>` error: aborting due to 3 previous errors diff --git a/tests/ui/wf/wf-convert-unsafe-trait-obj.stderr b/tests/ui/wf/wf-convert-unsafe-trait-obj.stderr index c9bd4549aaf..e2c71df2feb 100644 --- a/tests/ui/wf/wf-convert-unsafe-trait-obj.stderr +++ b/tests/ui/wf/wf-convert-unsafe-trait-obj.stderr @@ -11,8 +11,7 @@ LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | | this trait cannot be made into an object... - = note: required for `&S` to implement `CoerceUnsized<&dyn Trait>` - = note: required by cast to type `&dyn Trait` + = note: required for the cast from `&S` to `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-convert-unsafe-trait-obj.rs:17:17 @@ -27,8 +26,7 @@ LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | | this trait cannot be made into an object... - = note: required for `&S` to implement `CoerceUnsized<&dyn Trait>` - = note: required by cast to type `&dyn Trait` + = note: required for the cast from `&S` to `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-convert-unsafe-trait-obj.rs:15:5 @@ -43,8 +41,7 @@ LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | | this trait cannot be made into an object... - = note: required for `&S` to implement `CoerceUnsized<&dyn Trait>` - = note: required by cast to type `&dyn Trait` + = note: required for the cast from `&S` to `&dyn Trait` error: aborting due to 3 previous errors diff --git a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr index d2b41630976..66504e44060 100644 --- a/tests/ui/wf/wf-unsafe-trait-obj-match.stderr +++ b/tests/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -25,8 +25,7 @@ LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | | this trait cannot be made into an object... - = note: required for `&S` to implement `CoerceUnsized<&dyn Trait>` - = note: required by cast to type `&dyn Trait` + = note: required for the cast from `&S` to `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-unsafe-trait-obj-match.rs:25:25 @@ -45,8 +44,7 @@ LL | trait Trait: Sized {} | ----- ^^^^^ ...because it requires `Self: Sized` | | | this trait cannot be made into an object... - = note: required for `&R` to implement `CoerceUnsized<&dyn Trait>` - = note: required by cast to type `&dyn Trait` + = note: required for the cast from `&R` to `&dyn Trait` error: aborting due to 3 previous errors diff --git a/triagebot.toml b/triagebot.toml index 54c8b2060c5..d7cd3ea1275 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -371,31 +371,6 @@ cc = ["@GuillaumeGomez"] message = "Some changes might have occurred in exhaustiveness checking" cc = ["@Nadrieril"] -[mentions."library"] -message = """ -Hey! It looks like you've submitted a new PR for the library teams! - -If this PR contains changes to any `rust-lang/rust` public library APIs then \ -please comment with `@rustbot label +T-libs-api -T-libs` to tag it \ -appropriately. If this PR contains changes to any unstable APIs please edit \ -the PR description to add a link to the relevant [API Change \ -Proposal](https://std-dev-guide.rust-lang.org/feature-lifecycle/api-change-proposals.html) \ -or [create one](https://github.com/rust-lang/libs-team/issues/new?assignees=&labels=api-change-proposal%2C+T-libs-api&template=api-change-proposal.md&title=%28My+API+Change+Proposal%29) \ -if you haven't already. If you're unsure where your change falls no worries, \ -just leave it as is and the reviewer will take a look and make a decision to \ -forward on if necessary. - -Examples of `T-libs-api` changes: - -* Stabilizing library features -* Introducing insta-stable changes such as new implementations of existing \ - stable traits on existing stable types -* Introducing new or changing existing unstable library APIs (excluding \ - permanently unstable features / features without a tracking issue) -* Changing public documentation in ways that create new stability guarantees -* Changing observable runtime behavior of library APIs -""" - [mentions."src/librustdoc/clean/types.rs"] cc = ["@camelid"] @@ -507,11 +482,11 @@ compiler-team = [ "@petrochenkov", "@davidtwco", "@oli-obk", - "@lcnr", "@wesleywiser", ] compiler-team-contributors = [ "@compiler-errors", + "@eholk", "@jackh726", "@TaKO8Ki", "@WaffleLapkin", @@ -532,6 +507,7 @@ bootstrap = [ "@Mark-Simulacrum", "@albertlarsan68", "@ozkanonur", + "@clubby789", ] infra-ci = [ "@Mark-Simulacrum", @@ -616,6 +592,7 @@ style-team = [ "/compiler/rustc_llvm" = ["@cuviper"] "/compiler/rustc_middle/src/mir" = ["compiler", "mir"] "/compiler/rustc_middle/src/traits" = ["compiler", "types"] +"/compiler/rustc_middle/src/ty" = ["compiler", "types"] "/compiler/rustc_const_eval/src/interpret" = ["compiler", "mir"] "/compiler/rustc_const_eval/src/transform" = ["compiler", "mir-opt"] "/compiler/rustc_mir_build/src/build" = ["compiler", "mir"] |
