diff options
346 files changed, 7423 insertions, 4159 deletions
diff --git a/.mailmap b/.mailmap index 6e3eed1226e..0f7bc5e38bd 100644 --- a/.mailmap +++ b/.mailmap @@ -609,6 +609,7 @@ Shohei Wada <pc@wada314.jp> Shotaro Yamada <sinkuu@sinkuu.xyz> Shotaro Yamada <sinkuu@sinkuu.xyz> <sinkuu@users.noreply.github.com> Shyam Sundar B <shyambaskaran@outlook.com> +Sidney Cammeresi <sac@cheesecake.org> <sac@readyset.io> Simon Barber-Dueck <sbarberdueck@gmail.com> Simon BD <simon@server> Simon Sapin <simon@exyr.org> <simon.sapin@exyr.org> Simonas Kazlauskas <git@kazlauskas.me> Simonas Kazlauskas <github@kazlauskas.me> diff --git a/Cargo.lock b/Cargo.lock index 4677d34d2a6..d39cfefea0c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4817,9 +4817,9 @@ dependencies = [ [[package]] name = "rustfix" -version = "0.8.1" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81864b097046da5df3758fdc6e4822bbb70afa06317e8ca45ea1b51cb8c5e5a4" +checksum = "82fa69b198d894d84e23afde8e9ab2af4400b2cba20d6bf2b428a8b01c222c5a" dependencies = [ "serde", "serde_json", diff --git a/RELEASES.md b/RELEASES.md index 33abe45ce46..2b65d070d5f 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,129 @@ +Version 1.90 (2025-09-18) +========================== + +<a id="1.90-Language"></a> + +Language +-------- +- [Split up the `unknown_or_malformed_diagnostic_attributes` lint](https://github.com/rust-lang/rust/pull/140717). This lint has been split up into four finer-grained lints, with `unknown_or_malformed_diagnostic_attributes` now being the lint group that contains these lints: + 1. `unknown_diagnostic_attributes`: unknown to the current compiler + 2. `misplaced_diagnostic_attributes`: placed on the wrong item + 3. `malformed_diagnostic_attributes`: malformed attribute syntax or options + 4. `malformed_diagnostic_format_literals`: malformed format string literal +- [Allow constants whose final value has references to mutable/external memory, but reject such constants as patterns](https://github.com/rust-lang/rust/pull/140942) +- [Allow volatile access to non-Rust memory, including address 0](https://github.com/rust-lang/rust/pull/141260) + + +<a id="1.90-Compiler"></a> + +Compiler +-------- +- [Use `lld` by default on `x86_64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/140525). +- [Tier 3 `musl` targets now link dynamically by default](https://github.com/rust-lang/rust/pull/144410). Affected targets: + - `mips64-unknown-linux-muslabi64` + - `powerpc64-unknown-linux-musl` + - `powerpc-unknown-linux-musl` + - `powerpc-unknown-linux-muslspe` + - `riscv32gc-unknown-linux-musl` + - `s390x-unknown-linux-musl` + - `thumbv7neon-unknown-linux-musleabihf` + + +<a id="1.90-Platform-Support"></a> + +Platform Support +---------------- +- [Demote `x86_64-apple-darwin` to Tier 2 with host tools](https://github.com/rust-lang/rust/pull/145252) + + +Refer to Rust's [platform support page][platform-support-doc] +for more information on Rust's tiered platform support. + +[platform-support-doc]: https://doc.rust-lang.org/rustc/platform-support.html + +<a id="1.90-Libraries"></a> + +Libraries +--------- +- [Stabilize `u*::{checked,overflowing,saturating,wrapping}_sub_signed`](https://github.com/rust-lang/rust/issues/126043) +- [Allow comparisons between `CStr`, `CString`, and `Cow<CStr>`](https://github.com/rust-lang/rust/pull/137268) +- [Remove some unsized tuple impls since unsized tuples can't be constructed](https://github.com/rust-lang/rust/pull/138340) +- [Set `MSG_NOSIGNAL` for `UnixStream`](https://github.com/rust-lang/rust/pull/140005) +- [`proc_macro::Ident::new` now supports `$crate`.](https://github.com/rust-lang/rust/pull/141996) +- [Guarantee the pointer returned from `Thread::into_raw` has at least 8 bytes of alignment](https://github.com/rust-lang/rust/pull/143859) + + +<a id="1.90-Stabilized-APIs"></a> + +Stabilized APIs +--------------- + +- [`u{n}::checked_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.checked_sub_signed) +- [`u{n}::overflowing_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.overflowing_sub_signed) +- [`u{n}::saturating_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.saturating_sub_signed) +- [`u{n}::wrapping_sub_signed`](https://doc.rust-lang.org/stable/std/primitive.usize.html#method.wrapping_sub_signed) +- [`impl Copy for IntErrorKind`](https://doc.rust-lang.org/stable/std/num/enum.IntErrorKind.html#impl-Copy-for-IntErrorKind) +- [`impl Hash for IntErrorKind`](https://doc.rust-lang.org/stable/std/num/enum.IntErrorKind.html#impl-Hash-for-IntErrorKind) +- [`impl PartialEq<&CStr> for CStr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#impl-PartialEq%3C%26CStr%3E-for-CStr) +- [`impl PartialEq<CString> for CStr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#impl-PartialEq%3CCString%3E-for-CStr) +- [`impl PartialEq<Cow<CStr>> for CStr`](https://doc.rust-lang.org/stable/std/ffi/struct.CStr.html#impl-PartialEq%3CCow%3C'_,+CStr%3E%3E-for-CStr) +- [`impl PartialEq<&CStr> for CString`](https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#impl-PartialEq%3C%26CStr%3E-for-CString) +- [`impl PartialEq<CStr> for CString`](https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#impl-PartialEq%3CCStr%3E-for-CString) +- [`impl PartialEq<Cow<CStr>> for CString`](https://doc.rust-lang.org/stable/std/ffi/struct.CString.html#impl-PartialEq%3CCow%3C'_,+CStr%3E%3E-for-CString) +- [`impl PartialEq<&CStr> for Cow<CStr>`](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html#impl-PartialEq%3C%26CStr%3E-for-Cow%3C'_,+CStr%3E) +- [`impl PartialEq<CStr> for Cow<CStr>`](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html#impl-PartialEq%3CCStr%3E-for-Cow%3C'_,+CStr%3E) +- [`impl PartialEq<CString> for Cow<CStr>`](https://doc.rust-lang.org/stable/std/borrow/enum.Cow.html#impl-PartialEq%3CCString%3E-for-Cow%3C'_,+CStr%3E) + + +These previously stable APIs are now stable in const contexts: + +- [`<[T]>::reverse`](https://doc.rust-lang.org/stable/std/primitive.slice.html#method.reverse) +- [`f32::floor`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.floor) +- [`f32::ceil`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.ceil) +- [`f32::trunc`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.trunc) +- [`f32::fract`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.fract) +- [`f32::round`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.round) +- [`f32::round_ties_even`](https://doc.rust-lang.org/stable/std/primitive.f32.html#method.round_ties_even) +- [`f64::floor`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.floor) +- [`f64::ceil`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.ceil) +- [`f64::trunc`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.trunc) +- [`f64::fract`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.fract) +- [`f64::round`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.round) +- [`f64::round_ties_even`](https://doc.rust-lang.org/stable/std/primitive.f64.html#method.round_ties_even) + + +<a id="1.90-Cargo"></a> + +Cargo +----- +- [Add `http.proxy-cainfo` config for proxy certs](https://github.com/rust-lang/cargo/pull/15374/) +- [Use `gix` for `cargo package`](https://github.com/rust-lang/cargo/pull/15534/) +- [feat(publish): Stabilize multi-package publishing](https://github.com/rust-lang/cargo/pull/15636/) + +<a id="1.90-Rustdoc"></a> + +Rustdoc +----- +- [Add ways to collapse all impl blocks](https://github.com/rust-lang/rust/pull/141663). Previously the "Summary" button and "-" keyboard shortcut would never collapse `impl` blocks, now they do when shift is held +- [Display unsafe attributes with `unsafe()` wrappers](https://github.com/rust-lang/rust/pull/143662) + + +<a id="1.90-Compatibility-Notes"></a> + +Compatibility Notes +------------------- +- [Use `lld` by default on `x86_64-unknown-linux-gnu`](https://github.com/rust-lang/rust/pull/140525). + See also <https://blog.rust-lang.org/2025/09/01/rust-lld-on-1.90.0-stable/>. +- [Make `core::iter::Fuse`'s `Default` impl construct `I::default()` internally as promised in the docs instead of always being empty](https://github.com/rust-lang/rust/pull/140985) +- [Set `MSG_NOSIGNAL` for `UnixStream`](https://github.com/rust-lang/rust/pull/140005) + This may change program behavior but results in the same behavior as other primitives (e.g., stdout, network sockets). + Programs relying on signals to terminate them should update handling of sockets to handle errors on write by exiting. +- [On Unix `std::env::home_dir` will use the fallback if the `HOME` environment variable is empty](https://github.com/rust-lang/rust/pull/141840) +- We now [reject unsupported `extern "{abi}"`s consistently in all positions](https://github.com/rust-lang/rust/pull/142134). This primarily affects the use of implementing traits on an `extern "{abi}"` function pointer, like `extern "stdcall" fn()`, on a platform that doesn't support that, like aarch64-unknown-linux-gnu. Direct usage of these unsupported ABI strings by declaring or defining functions was already rejected, so this is only a change for consistency. +- [const-eval: error when initializing a static writes to that static](https://github.com/rust-lang/rust/pull/143084) +- [Check that the `proc_macro_derive` macro has correct arguments when applied to the crate root](https://github.com/rust-lang/rust/pull/143607) + + Version 1.89.0 (2025-08-07) ========================== diff --git a/bootstrap.example.toml b/bootstrap.example.toml index eac93957797..51529751dd5 100644 --- a/bootstrap.example.toml +++ b/bootstrap.example.toml @@ -859,6 +859,14 @@ # Trigger a `DebugBreak` after an internal compiler error during bootstrap on Windows #rust.break-on-ice = true +# Set the number of threads for the compiler frontend used during compilation of Rust code (passed to `-Zthreads`). +# The valid options are: +# 0 - Set the number of threads according to the detected number of threads of the host system +# 1 - Use a single thread for compilation of Rust code (the default) +# N - Number of threads used for compilation of Rust code +# +#rust.parallel-frontend-threads = 1 + # ============================================================================= # Distribution options # diff --git a/compiler/rustc_attr_parsing/messages.ftl b/compiler/rustc_attr_parsing/messages.ftl index 839a5d23c3b..81ec17077c1 100644 --- a/compiler/rustc_attr_parsing/messages.ftl +++ b/compiler/rustc_attr_parsing/messages.ftl @@ -122,6 +122,14 @@ attr_parsing_null_on_export = `export_name` may not contain null characters attr_parsing_null_on_link_section = `link_section` may not contain null characters +attr_parsing_null_on_objc_class = `objc::class!` may not contain null characters + +attr_parsing_null_on_objc_selector = `objc::selector!` may not contain null characters + +attr_parsing_objc_class_expected_string_literal = `objc::class!` expected a string literal + +attr_parsing_objc_selector_expected_string_literal = `objc::selector!` expected a string literal + attr_parsing_repr_ident = meta item in `repr` must be an identifier diff --git a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs index d5d51f2e79a..262b8213977 100644 --- a/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs +++ b/compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs @@ -2,7 +2,10 @@ use rustc_hir::attrs::{CoverageAttrKind, OptimizeAttr, SanitizerSet, UsedBy}; use rustc_session::parse::feature_err; use super::prelude::*; -use crate::session_diagnostics::{NakedFunctionIncompatibleAttribute, NullOnExport}; +use crate::session_diagnostics::{ + NakedFunctionIncompatibleAttribute, NullOnExport, NullOnObjcClass, NullOnObjcSelector, + ObjcClassExpectedStringLiteral, ObjcSelectorExpectedStringLiteral, +}; pub(crate) struct OptimizeParser; @@ -150,6 +153,70 @@ impl<S: Stage> SingleAttributeParser<S> for ExportNameParser { } } +pub(crate) struct ObjcClassParser; + +impl<S: Stage> SingleAttributeParser<S> for ObjcClassParser { + const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_class]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + let Some(classname) = nv.value_as_str() else { + // `#[rustc_objc_class = ...]` is expected to be used as an implementatioin detail + // inside a standard library macro, but `cx.expected_string_literal` exposes too much. + // Use a custom error message instead. + cx.emit_err(ObjcClassExpectedStringLiteral { span: nv.value_span }); + return None; + }; + if classname.as_str().contains('\0') { + // `#[rustc_objc_class = ...]` will be converted to a null-terminated string, + // so it may not contain any null characters. + cx.emit_err(NullOnObjcClass { span: nv.value_span }); + return None; + } + Some(AttributeKind::ObjcClass { classname, span: cx.attr_span }) + } +} + +pub(crate) struct ObjcSelectorParser; + +impl<S: Stage> SingleAttributeParser<S> for ObjcSelectorParser { + const PATH: &[rustc_span::Symbol] = &[sym::rustc_objc_selector]; + const ATTRIBUTE_ORDER: AttributeOrder = AttributeOrder::KeepInnermost; + const ON_DUPLICATE: OnDuplicate<S> = OnDuplicate::Error; + const ALLOWED_TARGETS: AllowedTargets = + AllowedTargets::AllowList(&[Allow(Target::ForeignStatic)]); + const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName"); + + fn convert(cx: &mut AcceptContext<'_, '_, S>, args: &ArgParser<'_>) -> Option<AttributeKind> { + let Some(nv) = args.name_value() else { + cx.expected_name_value(cx.attr_span, None); + return None; + }; + let Some(methname) = nv.value_as_str() else { + // `#[rustc_objc_selector = ...]` is expected to be used as an implementatioin detail + // inside a standard library macro, but `cx.expected_string_literal` exposes too much. + // Use a custom error message instead. + cx.emit_err(ObjcSelectorExpectedStringLiteral { span: nv.value_span }); + return None; + }; + if methname.as_str().contains('\0') { + // `#[rustc_objc_selector = ...]` will be converted to a null-terminated string, + // so it may not contain any null characters. + cx.emit_err(NullOnObjcSelector { span: nv.value_span }); + return None; + } + Some(AttributeKind::ObjcSelector { methname, span: cx.attr_span }) + } +} + #[derive(Default)] pub(crate) struct NakedParser { span: Option<Span>, diff --git a/compiler/rustc_attr_parsing/src/context.rs b/compiler/rustc_attr_parsing/src/context.rs index d7998048be5..58b13292484 100644 --- a/compiler/rustc_attr_parsing/src/context.rs +++ b/compiler/rustc_attr_parsing/src/context.rs @@ -20,8 +20,8 @@ use crate::attributes::allow_unstable::{ use crate::attributes::body::CoroutineParser; use crate::attributes::codegen_attrs::{ ColdParser, CoverageParser, ExportNameParser, ForceTargetFeatureParser, NakedParser, - NoMangleParser, OptimizeParser, SanitizeParser, TargetFeatureParser, TrackCallerParser, - UsedParser, + NoMangleParser, ObjcClassParser, ObjcSelectorParser, OptimizeParser, SanitizeParser, + TargetFeatureParser, TrackCallerParser, UsedParser, }; use crate::attributes::confusables::ConfusablesParser; use crate::attributes::crate_level::{ @@ -185,6 +185,8 @@ attribute_parsers!( Single<LinkageParser>, Single<MoveSizeLimitParser>, Single<MustUseParser>, + Single<ObjcClassParser>, + Single<ObjcSelectorParser>, Single<OptimizeParser>, Single<PathAttributeParser>, Single<PatternComplexityLimitParser>, diff --git a/compiler/rustc_attr_parsing/src/session_diagnostics.rs b/compiler/rustc_attr_parsing/src/session_diagnostics.rs index 32ea9005a97..2c2b14c8a68 100644 --- a/compiler/rustc_attr_parsing/src/session_diagnostics.rs +++ b/compiler/rustc_attr_parsing/src/session_diagnostics.rs @@ -460,6 +460,34 @@ pub(crate) struct NullOnLinkSection { } #[derive(Diagnostic)] +#[diag(attr_parsing_null_on_objc_class)] +pub(crate) struct NullOnObjcClass { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_null_on_objc_selector)] +pub(crate) struct NullOnObjcSelector { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_objc_class_expected_string_literal)] +pub(crate) struct ObjcClassExpectedStringLiteral { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(attr_parsing_objc_selector_expected_string_literal)] +pub(crate) struct ObjcSelectorExpectedStringLiteral { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(attr_parsing_stability_outside_std, code = E0734)] pub(crate) struct StabilityOutsideStd { #[primary_span] diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 5d2dda8b0e7..f196bd04d0e 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -1557,9 +1557,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, '_, 'tcx> { ); } - &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => { + &Rvalue::Discriminant(place) => { let af = match *rvalue { - Rvalue::Len(..) => Some(ArtificialField::ArrayLength), Rvalue::Discriminant(..) => None, _ => unreachable!(), }; diff --git a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs index 99dd0b2dd46..c2ad6fcb4b7 100644 --- a/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs +++ b/compiler/rustc_borrowck/src/polonius/legacy/loan_invalidations.rs @@ -306,16 +306,11 @@ impl<'a, 'tcx> LoanInvalidationsGenerator<'a, 'tcx> { self.consume_operand(location, op); } - &(Rvalue::Len(place) | Rvalue::Discriminant(place)) => { - let af = match rvalue { - Rvalue::Len(..) => Some(ArtificialField::ArrayLength), - Rvalue::Discriminant(..) => None, - _ => unreachable!(), - }; + &Rvalue::Discriminant(place) => { self.access_place( location, place, - (Shallow(af), Read(ReadKind::Copy)), + (Shallow(None), Read(ReadKind::Copy)), LocalMutationIsAllowed::No, ); } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 8c5447fe1e9..dcedf0b1532 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -1631,7 +1631,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { | Rvalue::BinaryOp(..) | Rvalue::RawPtr(..) | Rvalue::ThreadLocalRef(..) - | Rvalue::Len(..) | Rvalue::Discriminant(..) | Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {} } @@ -2201,7 +2200,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { | Rvalue::Repeat(..) | Rvalue::Ref(..) | Rvalue::RawPtr(..) - | Rvalue::Len(..) | Rvalue::Cast(..) | Rvalue::ShallowInitBox(..) | Rvalue::BinaryOp(..) diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs index dd8f0e46a0e..63342880b09 100644 --- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs +++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs @@ -51,43 +51,4 @@ pub(crate) fn expand_deriving_const_param_ty( }; trait_def.expand(cx, mitem, item, push); - - let trait_def = TraitDef { - span, - path: path_std!(marker::UnsizedConstParamTy), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: false, - additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))], - supports_unions: false, - methods: Vec::new(), - associated_types: Vec::new(), - is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), - }; - - trait_def.expand(cx, mitem, item, push); -} - -pub(crate) fn expand_deriving_unsized_const_param_ty( - cx: &ExtCtxt<'_>, - span: Span, - mitem: &MetaItem, - item: &Annotatable, - push: &mut dyn FnMut(Annotatable), - is_const: bool, -) { - let trait_def = TraitDef { - span, - path: path_std!(marker::UnsizedConstParamTy), - skip_path_as_bound: false, - needs_copy_as_bound_if_packed: false, - additional_bounds: vec![ty::Ty::Path(path_std!(cmp::Eq))], - supports_unions: false, - methods: Vec::new(), - associated_types: Vec::new(), - is_const, - is_staged_api_crate: cx.ecfg.features.staged_api(), - }; - - trait_def.expand(cx, mitem, item, push); } diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index 1bcea95fbb7..4541e2cd3b4 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -129,7 +129,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { Clone: clone::expand_deriving_clone, Copy: bounds::expand_deriving_copy, ConstParamTy: bounds::expand_deriving_const_param_ty, - UnsizedConstParamTy: bounds::expand_deriving_unsized_const_param_ty, Debug: debug::expand_deriving_debug, Default: default::expand_deriving_default, Eq: eq::expand_deriving_eq, diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs index 3a28dd7e73c..41e11e1de61 100644 --- a/compiler/rustc_codegen_cranelift/src/base.rs +++ b/compiler/rustc_codegen_cranelift/src/base.rs @@ -834,12 +834,6 @@ fn codegen_stmt<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, cur_block: Block, stmt: fx.bcx.ins().nop(); } } - Rvalue::Len(place) => { - let place = codegen_place(fx, place); - let usize_layout = fx.layout_of(fx.tcx.types.usize); - let len = codegen_array_len(fx, place); - lval.write_cvalue(fx, CValue::by_val(len, usize_layout)); - } Rvalue::ShallowInitBox(ref operand, content_ty) => { let content_ty = fx.monomorphize(content_ty); let box_layout = fx.layout_of(Ty::new_box(fx.tcx, content_ty)); diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs index eb0a5336a1f..84fa56cf903 100644 --- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs +++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs @@ -730,7 +730,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { if self.is_sized_indirect() { OperandValue::Ref(PlaceValue::new_sized(val, self.layout.align.abi)).store(bx, dst) } else if self.is_unsized_indirect() { - bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); + bug!("unsized `ArgAbi` cannot be stored"); } else if let PassMode::Cast { ref cast, .. } = self.mode { // FIXME(eddyb): Figure out when the simpler Store is safe, clang // uses it for i16 -> {i8, i8}, but not for i24 -> {i8, i8, i8}. @@ -797,12 +797,7 @@ impl<'gcc, 'tcx> ArgAbiExt<'gcc, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { OperandValue::Pair(next(), next()).store(bx, dst); } PassMode::Indirect { meta_attrs: Some(_), .. } => { - let place_val = PlaceValue { - llval: next(), - llextra: Some(next()), - align: self.layout.align.abi, - }; - OperandValue::Ref(place_val).store(bx, dst); + bug!("unsized `ArgAbi` cannot be stored"); } PassMode::Direct(_) | PassMode::Indirect { meta_attrs: None, .. } diff --git a/compiler/rustc_codegen_llvm/src/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs index ac7583f5666..11be7041167 100644 --- a/compiler/rustc_codegen_llvm/src/abi.rs +++ b/compiler/rustc_codegen_llvm/src/abi.rs @@ -215,9 +215,9 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { let align = attrs.pointee_align.unwrap_or(self.layout.align.abi); OperandValue::Ref(PlaceValue::new_sized(val, align)).store(bx, dst); } - // Unsized indirect qrguments + // Unsized indirect arguments cannot be stored PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { - bug!("unsized `ArgAbi` must be handled through `store_fn_arg`"); + bug!("unsized `ArgAbi` cannot be stored"); } PassMode::Cast { cast, pad_i32: _ } => { // The ABI mandates that the value is passed as a different struct representation. @@ -272,12 +272,7 @@ impl<'ll, 'tcx> ArgAbiExt<'ll, 'tcx> for ArgAbi<'tcx, Ty<'tcx>> { OperandValue::Pair(next(), next()).store(bx, dst); } PassMode::Indirect { attrs: _, meta_attrs: Some(_), on_stack: _ } => { - let place_val = PlaceValue { - llval: next(), - llextra: Some(next()), - align: self.layout.align.abi, - }; - OperandValue::Ref(place_val).store(bx, dst); + bug!("unsized `ArgAbi` cannot be stored"); } PassMode::Direct(_) | PassMode::Indirect { attrs: _, meta_attrs: None, on_stack: _ } diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 38c1d3b53e8..b79176e9098 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -240,6 +240,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { } InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { constraints.extend_from_slice(&[ + "~{fflags}".to_string(), "~{vtype}".to_string(), "~{vl}".to_string(), "~{vxsat}".to_string(), diff --git a/compiler/rustc_codegen_llvm/src/base.rs b/compiler/rustc_codegen_llvm/src/base.rs index 9cc5d8dbc21..978134cc32b 100644 --- a/compiler/rustc_codegen_llvm/src/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -109,18 +109,36 @@ pub(crate) fn compile_codegen_unit( attributes::apply_to_llfn(entry, llvm::AttributePlace::Function, &attrs); } + // Define Objective-C module info and module flags. Note, the module info will + // also be added to the `llvm.compiler.used` variable, created later. + // + // These are only necessary when we need the linker to do its Objective-C-specific + // magic. We could theoretically do it unconditionally, but at a slight cost to linker + // performance in the common case where it's unnecessary. + if !cx.objc_classrefs.borrow().is_empty() || !cx.objc_selrefs.borrow().is_empty() { + if cx.objc_abi_version() == 1 { + cx.define_objc_module_info(); + } + cx.add_objc_module_flags(); + } + // Finalize code coverage by injecting the coverage map. Note, the coverage map will // also be added to the `llvm.compiler.used` variable, created next. if cx.sess().instrument_coverage() { cx.coverageinfo_finalize(); } - // Create the llvm.used and llvm.compiler.used variables. + // Create the llvm.used variable. if !cx.used_statics.is_empty() { cx.create_used_variable_impl(c"llvm.used", &cx.used_statics); } - if !cx.compiler_used_statics.is_empty() { - cx.create_used_variable_impl(c"llvm.compiler.used", &cx.compiler_used_statics); + + // Create the llvm.compiler.used variable. + { + let compiler_used_statics = cx.compiler_used_statics.borrow(); + if !compiler_used_statics.is_empty() { + cx.create_used_variable_impl(c"llvm.compiler.used", &compiler_used_statics); + } } // Run replace-all-uses-with for statics that need it. This must diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs index 7d0691366e6..0f17cc9063a 100644 --- a/compiler/rustc_codegen_llvm/src/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -1091,16 +1091,11 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { ty: Ty<'tcx>, lhs: Self::Value, rhs: Self::Value, - ) -> Option<Self::Value> { - // FIXME: See comment on the definition of `three_way_compare`. - if crate::llvm_util::get_version() < (20, 0, 0) { - return None; - } - + ) -> Self::Value { let size = ty.primitive_size(self.tcx); let name = if ty.is_signed() { "llvm.scmp" } else { "llvm.ucmp" }; - Some(self.call_intrinsic(name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs])) + self.call_intrinsic(name, &[self.type_i8(), self.type_ix(size.bits())], &[lhs, rhs]) } /* Miscellaneous instructions */ diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs index 11b79a7fe68..aa2df46329f 100644 --- a/compiler/rustc_codegen_llvm/src/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -108,6 +108,10 @@ impl<'ll, CX: Borrow<SCx<'ll>>> GenericCx<'ll, CX> { bytes_in_context(self.llcx(), bytes) } + pub(crate) fn null_terminate_const_bytes(&self, bytes: &[u8]) -> &'ll Value { + null_terminate_bytes_in_context(self.llcx(), bytes) + } + pub(crate) fn const_get_elt(&self, v: &'ll Value, idx: u64) -> &'ll Value { unsafe { let idx = c_uint::try_from(idx).expect("LLVMGetAggregateElement index overflow"); @@ -381,6 +385,16 @@ pub(crate) fn bytes_in_context<'ll>(llcx: &'ll llvm::Context, bytes: &[u8]) -> & } } +pub(crate) fn null_terminate_bytes_in_context<'ll>( + llcx: &'ll llvm::Context, + bytes: &[u8], +) -> &'ll Value { + unsafe { + let ptr = bytes.as_ptr() as *const c_char; + llvm::LLVMConstStringInContext2(llcx, ptr, bytes.len(), FALSE) + } +} + pub(crate) fn named_struct<'ll>(ty: &'ll Type, elts: &[&'ll Value]) -> &'ll Value { let len = c_uint::try_from(elts.len()).expect("LLVMConstStructInContext elements len overflow"); unsafe { llvm::LLVMConstNamedStruct(ty, elts.as_ptr(), len) } diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index dc9bb743560..a110ecbb75d 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -16,6 +16,7 @@ use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::layout::{HasTypingEnv, LayoutOf}; use rustc_middle::ty::{self, Instance}; use rustc_middle::{bug, span_bug}; +use rustc_span::Symbol; use tracing::{debug, instrument, trace}; use crate::common::CodegenCx; @@ -331,6 +332,10 @@ impl<'ll> CodegenCx<'ll, '_> { } g + } else if let Some(classname) = fn_attrs.objc_class { + self.get_objc_classref(classname) + } else if let Some(methname) = fn_attrs.objc_selector { + self.get_objc_selref(methname) } else { check_and_apply_linkage(self, fn_attrs, llty, sym, def_id) }; @@ -543,8 +548,225 @@ impl<'ll> CodegenCx<'ll, '_> { /// Add a global value to a list to be stored in the `llvm.compiler.used` variable, /// an array of ptr. - pub(crate) fn add_compiler_used_global(&mut self, global: &'ll Value) { - self.compiler_used_statics.push(global); + pub(crate) fn add_compiler_used_global(&self, global: &'ll Value) { + self.compiler_used_statics.borrow_mut().push(global); + } + + // We do our best here to match what Clang does when compiling Objective-C natively. + // See Clang's `CGObjCCommonMac::CreateCStringLiteral`: + // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L4134 + fn define_objc_classname(&self, classname: &str) -> &'ll Value { + assert_eq!(self.objc_abi_version(), 1); + + let llval = self.null_terminate_const_bytes(classname.as_bytes()); + let llty = self.val_ty(llval); + let sym = self.generate_local_symbol_name("OBJC_CLASS_NAME_"); + let g = self.define_global(&sym, llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", sym); + }); + set_global_alignment(self, g, self.tcx.data_layout.i8_align.abi); + llvm::set_initializer(g, llval); + llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); + llvm::set_section(g, c"__TEXT,__cstring,cstring_literals"); + llvm::LLVMSetGlobalConstant(g, llvm::TRUE); + llvm::LLVMSetUnnamedAddress(g, llvm::UnnamedAddr::Global); + self.add_compiler_used_global(g); + + g + } + + // We do our best here to match what Clang does when compiling Objective-C natively. + // See Clang's `ObjCNonFragileABITypesHelper`: + // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L6052 + fn get_objc_class_t(&self) -> &'ll Type { + if let Some(class_t) = self.objc_class_t.get() { + return class_t; + } + + assert_eq!(self.objc_abi_version(), 2); + + // struct _class_t { + // struct _class_t* isa; + // struct _class_t* const superclass; + // void* cache; + // IMP* vtable; + // struct class_ro_t* ro; + // } + + let class_t = self.type_named_struct("struct._class_t"); + let els = [self.type_ptr(); 5]; + let packed = false; + self.set_struct_body(class_t, &els, packed); + + self.objc_class_t.set(Some(class_t)); + class_t + } + + // We do our best here to match what Clang does when compiling Objective-C natively. We + // deduplicate references within a CGU, but we need a reference definition in each referencing + // CGU. All attempts at using external references to a single reference definition result in + // linker errors. + fn get_objc_classref(&self, classname: Symbol) -> &'ll Value { + let mut classrefs = self.objc_classrefs.borrow_mut(); + if let Some(classref) = classrefs.get(&classname).copied() { + return classref; + } + + let g = match self.objc_abi_version() { + 1 => { + // See Clang's `CGObjCMac::EmitClassRefFromId`: + // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5205 + let llval = self.define_objc_classname(classname.as_str()); + let llty = self.type_ptr(); + let sym = self.generate_local_symbol_name("OBJC_CLASS_REFERENCES_"); + let g = self.define_global(&sym, llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", sym); + }); + set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); + llvm::set_initializer(g, llval); + llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); + llvm::set_section(g, c"__OBJC,__cls_refs,literal_pointers,no_dead_strip"); + self.add_compiler_used_global(g); + g + } + 2 => { + // See Clang's `CGObjCNonFragileABIMac::EmitClassRefFromId`: + // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L7423 + let llval = { + let extern_sym = format!("OBJC_CLASS_$_{}", classname.as_str()); + let extern_llty = self.get_objc_class_t(); + self.declare_global(&extern_sym, extern_llty) + }; + let llty = self.type_ptr(); + let sym = self.generate_local_symbol_name("OBJC_CLASSLIST_REFERENCES_$_"); + let g = self.define_global(&sym, llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", sym); + }); + set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); + llvm::set_initializer(g, llval); + llvm::set_linkage(g, llvm::Linkage::InternalLinkage); + llvm::set_section(g, c"__DATA,__objc_classrefs,regular,no_dead_strip"); + self.add_compiler_used_global(g); + g + } + _ => unreachable!(), + }; + + classrefs.insert(classname, g); + g + } + + // We do our best here to match what Clang does when compiling Objective-C natively. We + // deduplicate references within a CGU, but we need a reference definition in each referencing + // CGU. All attempts at using external references to a single reference definition result in + // linker errors. + // + // Newer versions of Apple Clang generate calls to `@"objc_msgSend$methname"` selector stub + // functions. We don't currently do that. The code we generate is closer to what Apple Clang + // generates with the `-fno-objc-msgsend-selector-stubs` option. + fn get_objc_selref(&self, methname: Symbol) -> &'ll Value { + let mut selrefs = self.objc_selrefs.borrow_mut(); + if let Some(selref) = selrefs.get(&methname).copied() { + return selref; + } + + let abi_version = self.objc_abi_version(); + + // See Clang's `CGObjCCommonMac::CreateCStringLiteral`: + // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L4134 + let methname_llval = self.null_terminate_const_bytes(methname.as_str().as_bytes()); + let methname_llty = self.val_ty(methname_llval); + let methname_sym = self.generate_local_symbol_name("OBJC_METH_VAR_NAME_"); + let methname_g = self.define_global(&methname_sym, methname_llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", methname_sym); + }); + set_global_alignment(self, methname_g, self.tcx.data_layout.i8_align.abi); + llvm::set_initializer(methname_g, methname_llval); + llvm::set_linkage(methname_g, llvm::Linkage::PrivateLinkage); + llvm::set_section( + methname_g, + match abi_version { + 1 => c"__TEXT,__cstring,cstring_literals", + 2 => c"__TEXT,__objc_methname,cstring_literals", + _ => unreachable!(), + }, + ); + llvm::LLVMSetGlobalConstant(methname_g, llvm::TRUE); + llvm::LLVMSetUnnamedAddress(methname_g, llvm::UnnamedAddr::Global); + self.add_compiler_used_global(methname_g); + + // See Clang's `CGObjCMac::EmitSelectorAddr`: + // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5243 + // And Clang's `CGObjCNonFragileABIMac::EmitSelectorAddr`: + // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L7586 + let selref_llval = methname_g; + let selref_llty = self.type_ptr(); + let selref_sym = self.generate_local_symbol_name("OBJC_SELECTOR_REFERENCES_"); + let selref_g = self.define_global(&selref_sym, selref_llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", selref_sym); + }); + set_global_alignment(self, selref_g, self.tcx.data_layout.pointer_align().abi); + llvm::set_initializer(selref_g, selref_llval); + llvm::set_externally_initialized(selref_g, true); + llvm::set_linkage( + selref_g, + match abi_version { + 1 => llvm::Linkage::PrivateLinkage, + 2 => llvm::Linkage::InternalLinkage, + _ => unreachable!(), + }, + ); + llvm::set_section( + selref_g, + match abi_version { + 1 => c"__OBJC,__message_refs,literal_pointers,no_dead_strip", + 2 => c"__DATA,__objc_selrefs,literal_pointers,no_dead_strip", + _ => unreachable!(), + }, + ); + self.add_compiler_used_global(selref_g); + + selrefs.insert(methname, selref_g); + selref_g + } + + // We do our best here to match what Clang does when compiling Objective-C natively. + // See Clang's `ObjCTypesHelper`: + // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5936 + // And Clang's `CGObjCMac::EmitModuleInfo`: + // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5151 + pub(crate) fn define_objc_module_info(&mut self) { + assert_eq!(self.objc_abi_version(), 1); + + // struct _objc_module { + // long version; // Hardcoded to 7 in Clang. + // long size; // sizeof(struct _objc_module) + // char* name; // Hardcoded to classname "" in Clang. + // struct _objc_symtab* symtab; // Null without class or category definitions. + // } + + let llty = self.type_named_struct("struct._objc_module"); + let i32_llty = self.type_i32(); + let ptr_llty = self.type_ptr(); + let packed = false; + self.set_struct_body(llty, &[i32_llty, i32_llty, ptr_llty, ptr_llty], packed); + + let version = self.const_uint(i32_llty, 7); + let size = self.const_uint(i32_llty, 16); + let name = self.define_objc_classname(""); + let symtab = self.const_null(ptr_llty); + let llval = crate::common::named_struct(llty, &[version, size, name, symtab]); + + let sym = "OBJC_MODULES"; + let g = self.define_global(&sym, llty).unwrap_or_else(|| { + bug!("symbol `{}` is already defined", sym); + }); + set_global_alignment(self, g, self.tcx.data_layout.pointer_align().abi); + llvm::set_initializer(g, llval); + llvm::set_linkage(g, llvm::Linkage::PrivateLinkage); + llvm::set_section(g, c"__OBJC,__module_info,regular,no_dead_strip"); + + self.add_compiler_used_global(g); } } diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index a69fa54a54a..4a8ea11a3a8 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -26,7 +26,7 @@ use rustc_session::config::{ BranchProtection, CFGuard, CFProtection, CrateType, DebugInfo, FunctionReturn, PAuthKey, PacRet, }; use rustc_span::source_map::Spanned; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::{DUMMY_SP, Span, Symbol}; use rustc_symbol_mangling::mangle_internal_symbol; use rustc_target::spec::{HasTargetSpec, RelocModel, SmallDataThresholdSupport, Target, TlsModel}; use smallvec::SmallVec; @@ -119,7 +119,7 @@ pub(crate) struct FullCx<'ll, 'tcx> { /// Statics that will be placed in the llvm.compiler.used variable /// See <https://llvm.org/docs/LangRef.html#the-llvm-compiler-used-global-variable> for details - pub compiler_used_statics: Vec<&'ll Value>, + pub compiler_used_statics: RefCell<Vec<&'ll Value>>, /// Mapping of non-scalar types to llvm types. pub type_lowering: RefCell<FxHashMap<(Ty<'tcx>, Option<VariantIdx>), &'ll Type>>, @@ -146,6 +146,15 @@ pub(crate) struct FullCx<'ll, 'tcx> { /// `global_asm!` needs to be able to find this new global so that it can /// compute the correct mangled symbol name to insert into the asm. pub renamed_statics: RefCell<FxHashMap<DefId, &'ll Value>>, + + /// Cached Objective-C class type + pub objc_class_t: Cell<Option<&'ll Type>>, + + /// Cache of Objective-C class references + pub objc_classrefs: RefCell<FxHashMap<Symbol, &'ll Value>>, + + /// Cache of Objective-C selector references + pub objc_selrefs: RefCell<FxHashMap<Symbol, &'ll Value>>, } fn to_llvm_tls_model(tls_model: TlsModel) -> llvm::ThreadLocalMode { @@ -172,35 +181,6 @@ pub(crate) unsafe fn create_module<'ll>( let mut target_data_layout = sess.target.data_layout.to_string(); let llvm_version = llvm_util::get_version(); - if llvm_version < (20, 0, 0) { - if sess.target.arch == "aarch64" || sess.target.arch.starts_with("arm64") { - // LLVM 20 defines three additional address spaces for alternate - // pointer kinds used in Windows. - // See https://github.com/llvm/llvm-project/pull/111879 - target_data_layout = - target_data_layout.replace("-p270:32:32-p271:32:32-p272:64:64", ""); - } - if sess.target.arch.starts_with("sparc") { - // LLVM 20 updates the sparc layout to correctly align 128 bit integers to 128 bit. - // See https://github.com/llvm/llvm-project/pull/106951 - target_data_layout = target_data_layout.replace("-i128:128", ""); - } - if sess.target.arch.starts_with("mips64") { - // LLVM 20 updates the mips64 layout to correctly align 128 bit integers to 128 bit. - // See https://github.com/llvm/llvm-project/pull/112084 - target_data_layout = target_data_layout.replace("-i128:128", ""); - } - if sess.target.arch.starts_with("powerpc64") { - // LLVM 20 updates the powerpc64 layout to correctly align 128 bit integers to 128 bit. - // See https://github.com/llvm/llvm-project/pull/118004 - target_data_layout = target_data_layout.replace("-i128:128", ""); - } - if sess.target.arch.starts_with("wasm32") || sess.target.arch.starts_with("wasm64") { - // LLVM 20 updates the wasm(32|64) layout to correctly align 128 bit integers to 128 bit. - // See https://github.com/llvm/llvm-project/pull/119204 - target_data_layout = target_data_layout.replace("-i128:128", ""); - } - } if llvm_version < (21, 0, 0) { if sess.target.arch == "nvptx64" { // LLVM 21 updated the default layout on nvptx: https://github.com/llvm/llvm-project/pull/124961 @@ -644,7 +624,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { const_globals: Default::default(), statics_to_rauw: RefCell::new(Vec::new()), used_statics: Vec::new(), - compiler_used_statics: Vec::new(), + compiler_used_statics: Default::default(), type_lowering: Default::default(), scalar_lltypes: Default::default(), coverage_cx, @@ -655,6 +635,9 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { intrinsics: Default::default(), local_gen_sym_counter: Cell::new(0), renamed_statics: Default::default(), + objc_class_t: Cell::new(None), + objc_classrefs: Default::default(), + objc_selrefs: Default::default(), }, PhantomData, ) @@ -679,6 +662,69 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { llvm::set_linkage(g, llvm::Linkage::AppendingLinkage); llvm::set_section(g, c"llvm.metadata"); } + + /// The Objective-C ABI that is used. + /// + /// This corresponds to the `-fobjc-abi-version=` flag in Clang / GCC. + pub(crate) fn objc_abi_version(&self) -> u32 { + assert!(self.tcx.sess.target.is_like_darwin); + if self.tcx.sess.target.arch == "x86" && self.tcx.sess.target.os == "macos" { + // 32-bit x86 macOS uses ABI version 1 (a.k.a. the "fragile ABI"). + 1 + } else { + // All other Darwin-like targets we support use ABI version 2 + // (a.k.a the "non-fragile ABI"). + 2 + } + } + + // We do our best here to match what Clang does when compiling Objective-C natively. + // See Clang's `CGObjCCommonMac::EmitImageInfo`: + // https://github.com/llvm/llvm-project/blob/llvmorg-20.1.8/clang/lib/CodeGen/CGObjCMac.cpp#L5085 + pub(crate) fn add_objc_module_flags(&self) { + let abi_version = self.objc_abi_version(); + + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Error, + "Objective-C Version", + abi_version, + ); + + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Error, + "Objective-C Image Info Version", + 0, + ); + + llvm::add_module_flag_str( + self.llmod, + llvm::ModuleFlagMergeBehavior::Error, + "Objective-C Image Info Section", + match abi_version { + 1 => "__OBJC,__image_info,regular", + 2 => "__DATA,__objc_imageinfo,regular,no_dead_strip", + _ => unreachable!(), + }, + ); + + if self.tcx.sess.target.env == "sim" { + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Error, + "Objective-C Is Simulated", + 1 << 5, + ); + } + + llvm::add_module_flag_u32( + self.llmod, + llvm::ModuleFlagMergeBehavior::Error, + "Objective-C Class Properties", + 1 << 6, + ); + } } impl<'ll> SimpleCx<'ll> { pub(crate) fn get_type_of_global(&self, val: &'ll Value) -> &'ll Type { diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index dc3a84b6a15..0903ddab285 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -32,9 +32,7 @@ use self::type_map::{DINodeCreationResult, Stub, UniqueTypeId}; use super::CodegenUnitDebugContext; use super::namespace::mangled_name_of_instance; use super::type_names::{compute_debuginfo_type_name, compute_debuginfo_vtable_name}; -use super::utils::{ - DIB, create_DIArray, debug_context, get_namespace_for_item, is_node_local_to_unit, -}; +use super::utils::{DIB, debug_context, get_namespace_for_item, is_node_local_to_unit}; use crate::common::{AsCCharPtr, CodegenCx}; use crate::debuginfo::dwarf_const; use crate::debuginfo::metadata::type_map::build_type_with_children; @@ -119,17 +117,17 @@ fn build_fixed_size_array_di_node<'ll, 'tcx>( .try_to_target_usize(cx.tcx) .expect("expected monomorphic const in codegen") as c_longlong; - let subrange = - unsafe { Some(llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound)) }; + let subrange = unsafe { llvm::LLVMRustDIBuilderGetOrCreateSubrange(DIB(cx), 0, upper_bound) }; + let subscripts = &[subrange]; - let subscripts = create_DIArray(DIB(cx), &[subrange]); let di_node = unsafe { - llvm::LLVMRustDIBuilderCreateArrayType( + llvm::LLVMDIBuilderCreateArrayType( DIB(cx), size.bits(), align.bits() as u32, element_type_di_node, - subscripts, + subscripts.as_ptr(), + subscripts.len() as c_uint, ) }; @@ -175,17 +173,13 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( "ptr_type={ptr_type}, pointee_type={pointee_type}", ); - let di_node = unsafe { - llvm::LLVMRustDIBuilderCreatePointerType( - DIB(cx), - pointee_type_di_node, - pointer_size.bits(), - pointer_align.abi.bits() as u32, - 0, // Ignore DWARF address space. - ptr_type_debuginfo_name.as_c_char_ptr(), - ptr_type_debuginfo_name.len(), - ) - }; + let di_node = create_pointer_type( + cx, + pointee_type_di_node, + pointer_size, + pointer_align.abi, + &ptr_type_debuginfo_name, + ); DINodeCreationResult { di_node, already_stored_in_typemap: false } } @@ -233,17 +227,13 @@ fn build_pointer_or_reference_di_node<'ll, 'tcx>( // The data pointer type is a regular, thin pointer, regardless of whether this // is a slice or a trait object. - let data_ptr_type_di_node = unsafe { - llvm::LLVMRustDIBuilderCreatePointerType( - DIB(cx), - pointee_type_di_node, - addr_field.size.bits(), - addr_field.align.abi.bits() as u32, - 0, // Ignore DWARF address space. - std::ptr::null(), - 0, - ) - }; + let data_ptr_type_di_node = create_pointer_type( + cx, + pointee_type_di_node, + addr_field.size, + addr_field.align.abi, + "", + ); smallvec![ build_field_di_node( @@ -318,7 +308,7 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( debug_context(cx).type_map.unique_id_to_di_node.borrow_mut().remove(&unique_type_id); - let fn_di_node = create_subroutine_type(cx, create_DIArray(DIB(cx), &signature_di_nodes[..])); + let fn_di_node = create_subroutine_type(cx, &signature_di_nodes[..]); // This is actually a function pointer, so wrap it in pointer DI. let name = compute_debuginfo_type_name(cx.tcx, fn_ty, false); @@ -329,26 +319,44 @@ fn build_subroutine_type_di_node<'ll, 'tcx>( } _ => unreachable!(), }; - let di_node = unsafe { - llvm::LLVMRustDIBuilderCreatePointerType( - DIB(cx), - fn_di_node, - size.bits(), - align.bits() as u32, - 0, // Ignore DWARF address space. - name.as_c_char_ptr(), - name.len(), - ) - }; + let di_node = create_pointer_type(cx, fn_di_node, size, align, &name); DINodeCreationResult::new(di_node, false) } pub(super) fn create_subroutine_type<'ll>( cx: &CodegenCx<'ll, '_>, - signature: &'ll DICompositeType, + signature: &[Option<&'ll llvm::Metadata>], ) -> &'ll DICompositeType { - unsafe { llvm::LLVMRustDIBuilderCreateSubroutineType(DIB(cx), signature) } + unsafe { + llvm::LLVMDIBuilderCreateSubroutineType( + DIB(cx), + None, // ("File" is ignored and has no effect) + signature.as_ptr(), + signature.len() as c_uint, + DIFlags::FlagZero, // (default value) + ) + } +} + +fn create_pointer_type<'ll>( + cx: &CodegenCx<'ll, '_>, + pointee_ty: &'ll llvm::Metadata, + size: Size, + align: Align, + name: &str, +) -> &'ll llvm::Metadata { + unsafe { + llvm::LLVMDIBuilderCreatePointerType( + DIB(cx), + pointee_ty, + size.bits(), + align.bits() as u32, + 0, // Ignore DWARF address space. + name.as_ptr(), + name.len(), + ) + } } /// Create debuginfo for `dyn SomeTrait` types. Currently these are empty structs @@ -834,12 +842,13 @@ fn create_basic_type<'ll, 'tcx>( encoding: u32, ) -> &'ll DIBasicType { unsafe { - llvm::LLVMRustDIBuilderCreateBasicType( + llvm::LLVMDIBuilderCreateBasicType( DIB(cx), - name.as_c_char_ptr(), + name.as_ptr(), name.len(), size.bits(), encoding, + DIFlags::FlagZero, ) } } diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs index 18a783a348a..37200fdc41a 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/type_map.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; +use libc::c_uint; use rustc_abi::{Align, Size, VariantIdx}; use rustc_data_structures::fingerprint::Fingerprint; use rustc_data_structures::fx::FxHashMap; @@ -9,7 +10,7 @@ use rustc_middle::bug; use rustc_middle::ty::{self, ExistentialTraitRef, Ty, TyCtxt}; use super::{DefinitionLocation, SmallVec, UNKNOWN_LINE_NUMBER, unknown_file_metadata}; -use crate::common::{AsCCharPtr, CodegenCx}; +use crate::common::CodegenCx; use crate::debuginfo::utils::{DIB, create_DIArray, debug_context}; use crate::llvm::debuginfo::{DIFlags, DIScope, DIType}; use crate::llvm::{self}; @@ -191,7 +192,7 @@ pub(super) fn stub<'ll, 'tcx>( containing_scope: Option<&'ll DIScope>, flags: DIFlags, ) -> StubInfo<'ll, 'tcx> { - let empty_array = create_DIArray(DIB(cx), &[]); + let no_elements: &[Option<&llvm::Metadata>] = &[]; let unique_type_id_str = unique_type_id.generate_unique_id_string(cx.tcx); let (file_metadata, line_number) = if let Some(def_location) = def_location { @@ -207,10 +208,10 @@ pub(super) fn stub<'ll, 'tcx>( _ => None, }; unsafe { - llvm::LLVMRustDIBuilderCreateStructType( + llvm::LLVMDIBuilderCreateStructType( DIB(cx), containing_scope, - name.as_c_char_ptr(), + name.as_ptr(), name.len(), file_metadata, line_number, @@ -218,28 +219,30 @@ pub(super) fn stub<'ll, 'tcx>( align.bits() as u32, flags, None, - empty_array, - 0, + no_elements.as_ptr(), + no_elements.len() as c_uint, + 0u32, // (Objective-C runtime version; default is 0) vtable_holder, - unique_type_id_str.as_c_char_ptr(), + unique_type_id_str.as_ptr(), unique_type_id_str.len(), ) } } Stub::Union => unsafe { - llvm::LLVMRustDIBuilderCreateUnionType( + llvm::LLVMDIBuilderCreateUnionType( DIB(cx), containing_scope, - name.as_c_char_ptr(), + name.as_ptr(), name.len(), file_metadata, line_number, size.bits(), align.bits() as u32, flags, - Some(empty_array), - 0, - unique_type_id_str.as_c_char_ptr(), + no_elements.as_ptr(), + no_elements.len() as c_uint, + 0u32, // (Objective-C runtime version; default is 0) + unique_type_id_str.as_ptr(), unique_type_id_str.len(), ) }, diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 79334f7f9fe..126082aa3aa 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -349,7 +349,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { let file_metadata = file_metadata(self, &loc.file); let function_type_metadata = - create_subroutine_type(self, get_function_signature(self, fn_abi)); + create_subroutine_type(self, &get_function_signature(self, fn_abi)); let mut name = String::with_capacity(64); type_names::push_item_name(tcx, def_id, false, &mut name); @@ -441,9 +441,9 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { fn get_function_signature<'ll, 'tcx>( cx: &CodegenCx<'ll, 'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, - ) -> &'ll DIArray { + ) -> Vec<Option<&'ll llvm::Metadata>> { if cx.sess().opts.debuginfo != DebugInfo::Full { - return create_DIArray(DIB(cx), &[]); + return vec![]; } let mut signature = Vec::with_capacity(fn_abi.args.len() + 1); @@ -484,7 +484,7 @@ impl<'ll, 'tcx> DebugInfoCodegenMethods<'tcx> for CodegenCx<'ll, 'tcx> { .extend(fn_abi.args.iter().map(|arg| Some(type_di_node(cx, arg.layout.ty)))); } - create_DIArray(DIB(cx), &signature[..]) + signature } fn get_template_parameters<'ll, 'tcx>( diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 0679f55ab7f..71d8b7d25fe 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -24,9 +24,9 @@ use rustc_target::spec::SymbolVisibility; use super::RustString; use super::debuginfo::{ - DIArray, DIBasicType, DIBuilder, DICompositeType, DIDerivedType, DIDescriptor, DIEnumerator, - DIFile, DIFlags, DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram, - DISubrange, DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind, + DIArray, DIBasicType, DIBuilder, DIDerivedType, DIDescriptor, DIEnumerator, DIFile, DIFlags, + DIGlobalVariableExpression, DILocation, DISPFlags, DIScope, DISubprogram, DISubrange, + DITemplateTypeParameter, DIType, DIVariable, DebugEmissionKind, DebugNameTableKind, }; use crate::llvm; @@ -1237,6 +1237,7 @@ unsafe extern "C" { pub(crate) safe fn LLVMSetGlobalConstant(GlobalVar: &Value, IsConstant: Bool); pub(crate) safe fn LLVMSetTailCall(CallInst: &Value, IsTailCall: Bool); pub(crate) safe fn LLVMSetTailCallKind(CallInst: &Value, kind: TailCallKind); + pub(crate) safe fn LLVMSetExternallyInitialized(GlobalVar: &Value, IsExtInit: Bool); // Operations on attributes pub(crate) fn LLVMCreateStringAttribute( @@ -1870,6 +1871,78 @@ unsafe extern "C" { Scope: &'ll Metadata, InlinedAt: Option<&'ll Metadata>, ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderCreateSubroutineType<'ll>( + Builder: &DIBuilder<'ll>, + File: Option<&'ll Metadata>, // (ignored and has no effect) + ParameterTypes: *const Option<&'ll Metadata>, + NumParameterTypes: c_uint, + Flags: DIFlags, // (default is `DIFlags::DIFlagZero`) + ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderCreateUnionType<'ll>( + Builder: &DIBuilder<'ll>, + Scope: Option<&'ll Metadata>, + Name: *const c_uchar, // See "PTR_LEN_STR". + NameLen: size_t, + File: &'ll Metadata, + LineNumber: c_uint, + SizeInBits: u64, + AlignInBits: u32, + Flags: DIFlags, + Elements: *const Option<&'ll Metadata>, + NumElements: c_uint, + RunTimeLang: c_uint, // (optional Objective-C runtime version; default is 0) + UniqueId: *const c_uchar, // See "PTR_LEN_STR". + UniqueIdLen: size_t, + ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderCreateArrayType<'ll>( + Builder: &DIBuilder<'ll>, + Size: u64, + Align: u32, + Ty: &'ll Metadata, + Subscripts: *const &'ll Metadata, + NumSubscripts: c_uint, + ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderCreateBasicType<'ll>( + Builder: &DIBuilder<'ll>, + Name: *const c_uchar, // See "PTR_LEN_STR". + NameLen: size_t, + SizeInBits: u64, + Encoding: c_uint, // (`LLVMDWARFTypeEncoding`) + Flags: DIFlags, // (default is `DIFlags::DIFlagZero`) + ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderCreatePointerType<'ll>( + Builder: &DIBuilder<'ll>, + PointeeTy: &'ll Metadata, + SizeInBits: u64, + AlignInBits: u32, + AddressSpace: c_uint, // (optional DWARF address space; default is 0) + Name: *const c_uchar, // See "PTR_LEN_STR". + NameLen: size_t, + ) -> &'ll Metadata; + + pub(crate) fn LLVMDIBuilderCreateStructType<'ll>( + Builder: &DIBuilder<'ll>, + Scope: Option<&'ll Metadata>, + Name: *const c_uchar, // See "PTR_LEN_STR". + NameLen: size_t, + File: &'ll Metadata, + LineNumber: c_uint, + SizeInBits: u64, + AlignInBits: u32, + Flags: DIFlags, + DerivedFrom: Option<&'ll Metadata>, + Elements: *const Option<&'ll Metadata>, + NumElements: c_uint, + RunTimeLang: c_uint, // (optional Objective-C runtime version; default is 0) + VTableHolder: Option<&'ll Metadata>, + UniqueId: *const c_uchar, // See "PTR_LEN_STR". + UniqueIdLen: size_t, + ) -> &'ll Metadata; } #[link(name = "llvm-wrapper", kind = "static")] @@ -2172,11 +2245,6 @@ unsafe extern "C" { SourceLen: size_t, ) -> &'a DIFile; - pub(crate) fn LLVMRustDIBuilderCreateSubroutineType<'a>( - Builder: &DIBuilder<'a>, - ParameterTypes: &'a DIArray, - ) -> &'a DICompositeType; - pub(crate) fn LLVMRustDIBuilderCreateFunction<'a>( Builder: &DIBuilder<'a>, Scope: &'a DIDescriptor, @@ -2210,14 +2278,6 @@ unsafe extern "C" { TParam: &'a DIArray, ) -> &'a DISubprogram; - pub(crate) fn LLVMRustDIBuilderCreateBasicType<'a>( - Builder: &DIBuilder<'a>, - Name: *const c_char, - NameLen: size_t, - SizeInBits: u64, - Encoding: c_uint, - ) -> &'a DIBasicType; - pub(crate) fn LLVMRustDIBuilderCreateTypedef<'a>( Builder: &DIBuilder<'a>, Type: &'a DIBasicType, @@ -2228,34 +2288,6 @@ unsafe extern "C" { Scope: Option<&'a DIScope>, ) -> &'a DIDerivedType; - pub(crate) fn LLVMRustDIBuilderCreatePointerType<'a>( - Builder: &DIBuilder<'a>, - PointeeTy: &'a DIType, - SizeInBits: u64, - AlignInBits: u32, - AddressSpace: c_uint, - Name: *const c_char, - NameLen: size_t, - ) -> &'a DIDerivedType; - - pub(crate) fn LLVMRustDIBuilderCreateStructType<'a>( - Builder: &DIBuilder<'a>, - Scope: Option<&'a DIDescriptor>, - Name: *const c_char, - NameLen: size_t, - File: &'a DIFile, - LineNumber: c_uint, - SizeInBits: u64, - AlignInBits: u32, - Flags: DIFlags, - DerivedFrom: Option<&'a DIType>, - Elements: &'a DIArray, - RunTimeLang: c_uint, - VTableHolder: Option<&'a DIType>, - UniqueId: *const c_char, - UniqueIdLen: size_t, - ) -> &'a DICompositeType; - pub(crate) fn LLVMRustDIBuilderCreateMemberType<'a>( Builder: &DIBuilder<'a>, Scope: &'a DIDescriptor, @@ -2335,14 +2367,6 @@ unsafe extern "C" { AlignInBits: u32, ) -> &'a DIVariable; - pub(crate) fn LLVMRustDIBuilderCreateArrayType<'a>( - Builder: &DIBuilder<'a>, - Size: u64, - AlignInBits: u32, - Ty: &'a DIType, - Subscripts: &'a DIArray, - ) -> &'a DIType; - pub(crate) fn LLVMRustDIBuilderGetOrCreateSubrange<'a>( Builder: &DIBuilder<'a>, Lo: i64, @@ -2388,22 +2412,6 @@ unsafe extern "C" { IsScoped: bool, ) -> &'a DIType; - pub(crate) fn LLVMRustDIBuilderCreateUnionType<'a>( - Builder: &DIBuilder<'a>, - Scope: Option<&'a DIScope>, - Name: *const c_char, - NameLen: size_t, - File: &'a DIFile, - LineNumber: c_uint, - SizeInBits: u64, - AlignInBits: u32, - Flags: DIFlags, - Elements: Option<&'a DIArray>, - RunTimeLang: c_uint, - UniqueId: *const c_char, - UniqueIdLen: size_t, - ) -> &'a DIType; - pub(crate) fn LLVMRustDIBuilderCreateVariantPart<'a>( Builder: &DIBuilder<'a>, Scope: &'a DIScope, diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs index d6974e22c85..1115d82fa85 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -258,6 +258,10 @@ pub(crate) fn set_alignment(llglobal: &Value, align: Align) { } } +pub(crate) fn set_externally_initialized(llglobal: &Value, is_ext_init: bool) { + LLVMSetExternallyInitialized(llglobal, is_ext_init.to_llvm_bool()); +} + /// Get the `name`d comdat from `llmod` and assign it to `llglobal`. /// /// Inserts the comdat into `llmod` if it does not exist. diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs index d927ffd78c2..8461c8b03d5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -246,9 +246,6 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea ("aarch64", "pmuv3") => Some(LLVMFeature::new("perfmon")), ("aarch64", "paca") => Some(LLVMFeature::new("pauth")), ("aarch64", "pacg") => Some(LLVMFeature::new("pauth")), - // Before LLVM 20 those two features were packaged together as b16b16 - ("aarch64", "sve-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")), - ("aarch64", "sme-b16b16") if get_version().0 < 20 => Some(LLVMFeature::new("b16b16")), ("aarch64", "flagm2") => Some(LLVMFeature::new("altnzcv")), // Rust ties fp and neon together. ("aarch64", "neon") => Some(LLVMFeature::with_dependencies( @@ -262,57 +259,17 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea // Filter out features that are not supported by the current LLVM version ("aarch64", "fpmr") => None, // only existed in 18 ("arm", "fp16") => Some(LLVMFeature::new("fullfp16")), - // NVPTX targets added in LLVM 20 - ("nvptx64", "sm_100") if get_version().0 < 20 => None, - ("nvptx64", "sm_100a") if get_version().0 < 20 => None, - ("nvptx64", "sm_101") if get_version().0 < 20 => None, - ("nvptx64", "sm_101a") if get_version().0 < 20 => None, - ("nvptx64", "sm_120") if get_version().0 < 20 => None, - ("nvptx64", "sm_120a") if get_version().0 < 20 => None, - ("nvptx64", "ptx86") if get_version().0 < 20 => None, - ("nvptx64", "ptx87") if get_version().0 < 20 => None, // Filter out features that are not supported by the current LLVM version - ("loongarch64", "div32" | "lam-bh" | "lamcas" | "ld-seq-sa" | "scq") - if get_version().0 < 20 => - { - None - } ("loongarch32" | "loongarch64", "32s") if get_version().0 < 21 => None, - // Filter out features that are not supported by the current LLVM version - ("riscv32" | "riscv64", "zacas" | "rva23u64" | "supm") if get_version().0 < 20 => None, - ( - "s390x", - "message-security-assist-extension12" - | "concurrent-functions" - | "miscellaneous-extensions-4" - | "vector-enhancements-3" - | "vector-packed-decimal-enhancement-3", - ) if get_version().0 < 20 => None, // Enable the evex512 target feature if an avx512 target feature is enabled. ("x86", s) if s.starts_with("avx512") => Some(LLVMFeature::with_dependencies( s, smallvec![TargetFeatureFoldStrength::EnableOnly("evex512")], )), - // Support for `wide-arithmetic` will first land in LLVM 20 as part of - // llvm/llvm-project#111598 - ("wasm32" | "wasm64", "wide-arithmetic") if get_version() < (20, 0, 0) => None, ("sparc", "leoncasa") => Some(LLVMFeature::new("hasleoncasa")), - // In LLVM 19, there is no `v8plus` feature and `v9` means "SPARC-V9 instruction available and SPARC-V8+ ABI used". - // https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp#L27-L28 - // Before LLVM 19, there was no `v8plus` feature and `v9` means "SPARC-V9 instruction available". - // https://github.com/llvm/llvm-project/blob/llvmorg-18.1.0/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp#L26 - ("sparc", "v8plus") if get_version().0 == 19 => Some(LLVMFeature::new("v9")), ("powerpc", "power8-crypto") => Some(LLVMFeature::new("crypto")), - // These new `amx` variants and `movrs` were introduced in LLVM20 - ("x86", "amx-avx512" | "amx-fp8" | "amx-movrs" | "amx-tf32" | "amx-transpose") - if get_version().0 < 20 => - { - None - } - ("x86", "movrs") if get_version().0 < 20 => None, ("x86", "avx10.1") => Some(LLVMFeature::new("avx10.1-512")), - ("x86", "avx10.2") if get_version().0 < 20 => None, - ("x86", "avx10.2") if get_version().0 >= 20 => Some(LLVMFeature::new("avx10.2-512")), + ("x86", "avx10.2") => Some(LLVMFeature::new("avx10.2-512")), ("x86", "apxf") => Some(LLVMFeature::with_dependencies( "egpr", smallvec![ @@ -716,17 +673,7 @@ pub(crate) fn global_llvm_features( }; // Features implied by an implicit or explicit `--target`. - features.extend( - sess.target - .features - .split(',') - .filter(|v| !v.is_empty()) - // Drop +v8plus feature introduced in LLVM 20. - // (Hard-coded target features do not go through `to_llvm_feature` since they already - // are LLVM feature names, hence we need a special case here.) - .filter(|v| *v != "+v8plus" || get_version() >= (20, 0, 0)) - .map(String::from), - ); + features.extend(sess.target.features.split(',').filter(|v| !v.is_empty()).map(String::from)); if wants_wasm_eh(sess) && sess.panic_strategy() == PanicStrategy::Unwind { features.push("+exception-handling".into()); diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index dc500c363f4..32ae810ecc8 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -296,6 +296,12 @@ fn process_builtin_attrs( AttributeKind::Sanitize { span, .. } => { interesting_spans.sanitize = Some(*span); } + AttributeKind::ObjcClass { classname, .. } => { + codegen_fn_attrs.objc_class = Some(*classname); + } + AttributeKind::ObjcSelector { methname, .. } => { + codegen_fn_attrs.objc_selector = Some(*methname); + } _ => {} } } diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index f6f2e3f2a3a..2602bf82095 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -1,5 +1,5 @@ use itertools::Itertools as _; -use rustc_abi::{self as abi, FIRST_VARIANT}; +use rustc_abi::{self as abi, BackendRepr, FIRST_VARIANT}; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::layout::{HasTyCtxt, HasTypingEnv, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; @@ -7,9 +7,9 @@ use rustc_middle::{bug, mir, span_bug}; use rustc_session::config::OptLevel; use tracing::{debug, instrument}; +use super::FunctionCx; use super::operand::{OperandRef, OperandRefBuilder, OperandValue}; use super::place::{PlaceRef, PlaceValue, codegen_tag_value}; -use super::{FunctionCx, LocalRef}; use crate::common::{IntPredicate, TypeKind}; use crate::traits::*; use crate::{MemFlags, base}; @@ -25,6 +25,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { match *rvalue { mir::Rvalue::Use(ref operand) => { let cg_operand = self.codegen_operand(bx, operand); + // Crucially, we do *not* use `OperandValue::Ref` for types with + // `BackendRepr::Scalar | BackendRepr::ScalarPair`. This ensures we match the MIR + // semantics regarding when assignment operators allow overlap of LHS and RHS. + if matches!( + cg_operand.layout.backend_repr, + BackendRepr::Scalar(..) | BackendRepr::ScalarPair(..), + ) { + debug_assert!(!matches!(cg_operand.val, OperandValue::Ref(..))); + } // FIXME: consider not copying constants through stack. (Fixable by codegen'ing // constants into `OperandValue::Ref`; why don’t we do that yet if we don’t?) cg_operand.val.store(bx, dest); @@ -501,14 +510,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { self.codegen_place_to_pointer(bx, place, mk_ptr) } - mir::Rvalue::Len(place) => { - let size = self.evaluate_array_len(bx, place); - OperandRef { - val: OperandValue::Immediate(size), - layout: bx.cx().layout_of(bx.tcx().types.usize), - } - } - mir::Rvalue::BinaryOp(op_with_overflow, box (ref lhs, ref rhs)) if let Some(op) = op_with_overflow.overflowing_to_wrapping() => { @@ -740,21 +741,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } - fn evaluate_array_len(&mut self, bx: &mut Bx, place: mir::Place<'tcx>) -> Bx::Value { - // ZST are passed as operands and require special handling - // because codegen_place() panics if Local is operand. - if let Some(index) = place.as_local() - && let LocalRef::Operand(op) = self.locals[index] - && let ty::Array(_, n) = op.layout.ty.kind() - { - let n = n.try_to_target_usize(bx.tcx()).expect("expected monomorphic const in codegen"); - return bx.cx().const_usize(n); - } - // use common size calculation for non zero-sized types - let cg_value = self.codegen_place(bx, place.as_ref()); - cg_value.len(bx.cx()) - } - /// Codegen an `Rvalue::RawPtr` or `Rvalue::Ref` fn codegen_place_to_pointer( &mut self, @@ -892,36 +878,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } mir::BinOp::Cmp => { - use std::cmp::Ordering; assert!(!is_float); - if let Some(value) = bx.three_way_compare(lhs_ty, lhs, rhs) { - return value; - } - let pred = |op| base::bin_op_to_icmp_predicate(op, is_signed); - if bx.cx().tcx().sess.opts.optimize == OptLevel::No { - // FIXME: This actually generates tighter assembly, and is a classic trick - // <https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign> - // However, as of 2023-11 it optimizes worse in things like derived - // `PartialOrd`, so only use it in debug for now. Once LLVM can handle it - // better (see <https://github.com/llvm/llvm-project/issues/73417>), it'll - // be worth trying it in optimized builds as well. - let is_gt = bx.icmp(pred(mir::BinOp::Gt), lhs, rhs); - let gtext = bx.zext(is_gt, bx.type_i8()); - let is_lt = bx.icmp(pred(mir::BinOp::Lt), lhs, rhs); - let ltext = bx.zext(is_lt, bx.type_i8()); - bx.unchecked_ssub(gtext, ltext) - } else { - // These operations are those expected by `tests/codegen-llvm/integer-cmp.rs`, - // from <https://github.com/rust-lang/rust/pull/63767>. - let is_lt = bx.icmp(pred(mir::BinOp::Lt), lhs, rhs); - let is_ne = bx.icmp(pred(mir::BinOp::Ne), lhs, rhs); - let ge = bx.select( - is_ne, - bx.cx().const_i8(Ordering::Greater as i8), - bx.cx().const_i8(Ordering::Equal as i8), - ); - bx.select(is_lt, bx.cx().const_i8(Ordering::Less as i8), ge) - } + bx.three_way_compare(lhs_ty, lhs, rhs) } mir::BinOp::AddWithOverflow | mir::BinOp::SubWithOverflow diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs index f417d1a7bf7..4a5694e97fa 100644 --- a/compiler/rustc_codegen_ssa/src/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -3,6 +3,7 @@ use std::ops::Deref; use rustc_abi::{Align, Scalar, Size, WrappingRange}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs; +use rustc_middle::mir; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf, TyAndLayout}; use rustc_middle::ty::{AtomicOrdering, Instance, Ty}; use rustc_session::config::OptLevel; @@ -405,15 +406,41 @@ pub trait BuilderMethods<'a, 'tcx>: fn fcmp(&mut self, op: RealPredicate, lhs: Self::Value, rhs: Self::Value) -> Self::Value; /// Returns `-1` if `lhs < rhs`, `0` if `lhs == rhs`, and `1` if `lhs > rhs`. - // FIXME: Move the default implementation from `codegen_scalar_binop` into this method and - // remove the `Option` return once LLVM 20 is the minimum version. fn three_way_compare( &mut self, - _ty: Ty<'tcx>, - _lhs: Self::Value, - _rhs: Self::Value, - ) -> Option<Self::Value> { - None + ty: Ty<'tcx>, + lhs: Self::Value, + rhs: Self::Value, + ) -> Self::Value { + // FIXME: This implementation was designed around LLVM's ability to optimize, but `cg_llvm` + // overrides this to just use `@llvm.scmp`/`ucmp` since LLVM 20. This default impl should be + // reevaluated with respect to the remaining backends like cg_gcc, whether they might use + // specialized implementations as well, or continue to use a generic implementation here. + use std::cmp::Ordering; + let pred = |op| crate::base::bin_op_to_icmp_predicate(op, ty.is_signed()); + if self.cx().sess().opts.optimize == OptLevel::No { + // This actually generates tighter assembly, and is a classic trick: + // <https://graphics.stanford.edu/~seander/bithacks.html#CopyIntegerSign>. + // However, as of 2023-11 it optimized worse in LLVM in things like derived + // `PartialOrd`, so we were only using it in debug. Since LLVM now uses its own + // intrinsics, it may be be worth trying it in optimized builds for other backends. + let is_gt = self.icmp(pred(mir::BinOp::Gt), lhs, rhs); + let gtext = self.zext(is_gt, self.type_i8()); + let is_lt = self.icmp(pred(mir::BinOp::Lt), lhs, rhs); + let ltext = self.zext(is_lt, self.type_i8()); + self.unchecked_ssub(gtext, ltext) + } else { + // These operations were better optimized by LLVM, before `@llvm.scmp`/`ucmp` in 20. + // See <https://github.com/rust-lang/rust/pull/63767>. + let is_lt = self.icmp(pred(mir::BinOp::Lt), lhs, rhs); + let is_ne = self.icmp(pred(mir::BinOp::Ne), lhs, rhs); + let ge = self.select( + is_ne, + self.cx().const_i8(Ordering::Greater as i8), + self.cx().const_i8(Ordering::Equal as i8), + ); + self.select(is_lt, self.cx().const_i8(Ordering::Less as i8), ge) + } } fn memcpy( diff --git a/compiler/rustc_const_eval/src/check_consts/check.rs b/compiler/rustc_const_eval/src/check_consts/check.rs index ca707b50d50..3397bd9a68e 100644 --- a/compiler/rustc_const_eval/src/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/check_consts/check.rs @@ -573,8 +573,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { Rvalue::Use(_) | Rvalue::CopyForDeref(..) | Rvalue::Repeat(..) - | Rvalue::Discriminant(..) - | Rvalue::Len(_) => {} + | Rvalue::Discriminant(..) => {} Rvalue::Aggregate(kind, ..) => { if let AggregateKind::Coroutine(def_id, ..) = kind.as_ref() diff --git a/compiler/rustc_const_eval/src/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/check_consts/qualifs.rs index faf41f1658b..34d1fdd8c86 100644 --- a/compiler/rustc_const_eval/src/check_consts/qualifs.rs +++ b/compiler/rustc_const_eval/src/check_consts/qualifs.rs @@ -232,9 +232,7 @@ where Q::in_any_value_of_ty(cx, rvalue.ty(cx.body, cx.tcx)) } - Rvalue::Discriminant(place) | Rvalue::Len(place) => { - in_place::<Q, _>(cx, in_local, place.as_ref()) - } + Rvalue::Discriminant(place) => in_place::<Q, _>(cx, in_local, place.as_ref()), Rvalue::CopyForDeref(place) => in_place::<Q, _>(cx, in_local, place.as_ref()), diff --git a/compiler/rustc_const_eval/src/check_consts/resolver.rs b/compiler/rustc_const_eval/src/check_consts/resolver.rs index d98e5027e4d..664dda8701a 100644 --- a/compiler/rustc_const_eval/src/check_consts/resolver.rs +++ b/compiler/rustc_const_eval/src/check_consts/resolver.rs @@ -197,7 +197,6 @@ where | mir::Rvalue::CopyForDeref(..) | mir::Rvalue::ThreadLocalRef(..) | mir::Rvalue::Repeat(..) - | mir::Rvalue::Len(..) | mir::Rvalue::BinaryOp(..) | mir::Rvalue::NullaryOp(..) | mir::Rvalue::UnaryOp(..) diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs index ebcdb9461d0..323e1cefd58 100644 --- a/compiler/rustc_const_eval/src/interpret/memory.rs +++ b/compiler/rustc_const_eval/src/interpret/memory.rs @@ -1504,7 +1504,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { // This will also error if copying partial provenance is not supported. let provenance = src_alloc .provenance() - .prepare_copy(src_range, dest_offset, num_copies, self) + .prepare_copy(src_range, self) .map_err(|e| e.to_interp_error(src_alloc_id))?; // Prepare a copy of the initialization mask. let init = src_alloc.init_mask().prepare_copy(src_range); @@ -1590,7 +1590,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { num_copies, ); // copy the provenance to the destination - dest_alloc.provenance_apply_copy(provenance); + dest_alloc.provenance_apply_copy(provenance, alloc_range(dest_offset, size), num_copies); interp_ok(()) } diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs index a86fdf80f60..cd34892f029 100644 --- a/compiler/rustc_const_eval/src/interpret/place.rs +++ b/compiler/rustc_const_eval/src/interpret/place.rs @@ -858,7 +858,7 @@ where /// Also, if you use this you are responsible for validating that things get copied at the /// right type. #[instrument(skip(self), level = "trace")] - fn copy_op_no_validate( + pub(super) fn copy_op_no_validate( &mut self, src: &impl Projectable<'tcx, M::Provenance>, dest: &impl Writeable<'tcx, M::Provenance>, diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs index 23d362de308..923e00ad4cf 100644 --- a/compiler/rustc_const_eval/src/interpret/step.rs +++ b/compiler/rustc_const_eval/src/interpret/step.rs @@ -17,7 +17,7 @@ use tracing::{info, instrument, trace}; use super::{ FnArg, FnVal, ImmTy, Immediate, InterpCx, InterpResult, Machine, MemPlaceMeta, PlaceTy, - Projectable, Scalar, interp_ok, throw_ub, throw_unsup_format, + Projectable, interp_ok, throw_ub, throw_unsup_format, }; use crate::interpret::EnteredTraceSpan; use crate::{enter_trace_span, util}; @@ -225,12 +225,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.write_repeat(operand, &dest)?; } - Len(place) => { - let src = self.eval_place(place)?; - let len = src.len(self)?; - self.write_scalar(Scalar::from_target_usize(len, self), &dest)?; - } - Ref(_, borrow_kind, place) => { let src = self.eval_place(place)?; let place = self.force_allocation(&src)?; @@ -310,7 +304,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { operands: &IndexSlice<FieldIdx, mir::Operand<'tcx>>, dest: &PlaceTy<'tcx, M::Provenance>, ) -> InterpResult<'tcx> { - self.write_uninit(dest)?; // make sure all the padding ends up as uninit let (variant_index, variant_dest, active_field_index) = match *kind { mir::AggregateKind::Adt(_, variant_index, _, _, active_field_index) => { let variant_dest = self.project_downcast(dest, variant_index)?; @@ -346,9 +339,20 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { let field_index = active_field_index.unwrap_or(field_index); let field_dest = self.project_field(&variant_dest, field_index)?; let op = self.eval_operand(operand, Some(field_dest.layout))?; - self.copy_op(&op, &field_dest)?; + // We validate manually below so we don't have to do it here. + self.copy_op_no_validate(&op, &field_dest, /*allow_transmute*/ false)?; } - self.write_discriminant(variant_index, dest) + self.write_discriminant(variant_index, dest)?; + // Validate that the entire thing is valid, and reset padding that might be in between the + // fields. + if M::enforce_validity(self, dest.layout()) { + self.validate_operand( + dest, + M::enforce_validity_recursively(self, dest.layout()), + /*reset_provenance_and_padding*/ true, + )?; + } + interp_ok(()) } /// Repeats `operand` into the destination. `dest` must have array type, and that type diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs index 17da3ea83c8..e4e86bcc41a 100644 --- a/compiler/rustc_data_structures/src/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -34,6 +34,7 @@ #![feature(sized_hierarchy)] #![feature(test)] #![feature(thread_id_value)] +#![feature(trusted_len)] #![feature(type_alias_impl_trait)] #![feature(unwrap_infallible)] // tidy-alphabetical-end diff --git a/compiler/rustc_data_structures/src/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs index c002d47815b..15e3e6ea4c3 100644 --- a/compiler/rustc_data_structures/src/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -1,6 +1,7 @@ use std::borrow::Borrow; use std::cmp::Ordering; use std::fmt::Debug; +use std::iter::TrustedLen; use std::mem; use std::ops::{Bound, Index, IndexMut, RangeBounds}; @@ -215,36 +216,40 @@ impl<K: Ord, V> SortedMap<K, V> { /// It is up to the caller to make sure that the elements are sorted by key /// and that there are no duplicates. #[inline] - pub fn insert_presorted(&mut self, elements: Vec<(K, V)>) { - if elements.is_empty() { + pub fn insert_presorted( + &mut self, + // We require `TrustedLen` to ensure that the `splice` below is actually efficient. + mut elements: impl Iterator<Item = (K, V)> + DoubleEndedIterator + TrustedLen, + ) { + let Some(first) = elements.next() else { return; - } - - debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0)); + }; - let start_index = self.lookup_index_for(&elements[0].0); + let start_index = self.lookup_index_for(&first.0); let elements = match start_index { Ok(index) => { - let mut elements = elements.into_iter(); - self.data[index] = elements.next().unwrap(); - elements + self.data[index] = first; // overwrite first element + elements.chain(None) // insert the rest below } Err(index) => { - if index == self.data.len() || elements.last().unwrap().0 < self.data[index].0 { + let last = elements.next_back(); + if index == self.data.len() + || last.as_ref().is_none_or(|l| l.0 < self.data[index].0) + { // We can copy the whole range without having to mix with // existing elements. - self.data.splice(index..index, elements); + self.data + .splice(index..index, std::iter::once(first).chain(elements).chain(last)); return; } - let mut elements = elements.into_iter(); - self.data.insert(index, elements.next().unwrap()); - elements + self.data.insert(index, first); + elements.chain(last) // insert the rest below } }; - // Insert the rest + // Insert the rest. This is super inefficicent since each insertion copies the entire tail. for (k, v) in elements { self.insert(k, v); } diff --git a/compiler/rustc_data_structures/src/sorted_map/tests.rs b/compiler/rustc_data_structures/src/sorted_map/tests.rs index ea4d2f1feac..17d0d3cb170 100644 --- a/compiler/rustc_data_structures/src/sorted_map/tests.rs +++ b/compiler/rustc_data_structures/src/sorted_map/tests.rs @@ -171,7 +171,7 @@ fn test_insert_presorted_non_overlapping() { map.insert(2, 0); map.insert(8, 0); - map.insert_presorted(vec![(3, 0), (7, 0)]); + map.insert_presorted(vec![(3, 0), (7, 0)].into_iter()); let expected = vec![2, 3, 7, 8]; assert_eq!(keys(map), expected); @@ -183,7 +183,7 @@ fn test_insert_presorted_first_elem_equal() { map.insert(2, 2); map.insert(8, 8); - map.insert_presorted(vec![(2, 0), (7, 7)]); + map.insert_presorted(vec![(2, 0), (7, 7)].into_iter()); let expected = vec![(2, 0), (7, 7), (8, 8)]; assert_eq!(elements(map), expected); @@ -195,7 +195,7 @@ fn test_insert_presorted_last_elem_equal() { map.insert(2, 2); map.insert(8, 8); - map.insert_presorted(vec![(3, 3), (8, 0)]); + map.insert_presorted(vec![(3, 3), (8, 0)].into_iter()); let expected = vec![(2, 2), (3, 3), (8, 0)]; assert_eq!(elements(map), expected); @@ -207,7 +207,7 @@ fn test_insert_presorted_shuffle() { map.insert(2, 2); map.insert(7, 7); - map.insert_presorted(vec![(1, 1), (3, 3), (8, 8)]); + map.insert_presorted(vec![(1, 1), (3, 3), (8, 8)].into_iter()); let expected = vec![(1, 1), (2, 2), (3, 3), (7, 7), (8, 8)]; assert_eq!(elements(map), expected); @@ -219,7 +219,7 @@ fn test_insert_presorted_at_end() { map.insert(1, 1); map.insert(2, 2); - map.insert_presorted(vec![(3, 3), (8, 8)]); + map.insert_presorted(vec![(3, 3), (8, 8)].into_iter()); let expected = vec![(1, 1), (2, 2), (3, 3), (8, 8)]; assert_eq!(elements(map), expected); diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 129ab7eccb5..99d6e93faa9 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -1057,6 +1057,14 @@ pub static BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_std_internal_symbol, Normal, template!(Word), WarnFollowing, EncodeCrossCrate::No, ), + rustc_attr!( + rustc_objc_class, Normal, template!(NameValueStr: "ClassName"), ErrorPreceding, + EncodeCrossCrate::No, + ), + rustc_attr!( + rustc_objc_selector, Normal, template!(NameValueStr: "methodName"), ErrorPreceding, + EncodeCrossCrate::No, + ), // ========================================================================== // Internal attributes, Macro related: diff --git a/compiler/rustc_hir/src/attrs/data_structures.rs b/compiler/rustc_hir/src/attrs/data_structures.rs index ea11a99efbc..04b144abd03 100644 --- a/compiler/rustc_hir/src/attrs/data_structures.rs +++ b/compiler/rustc_hir/src/attrs/data_structures.rs @@ -594,6 +594,12 @@ pub enum AttributeKind { /// Represents `#[non_exhaustive]` NonExhaustive(Span), + /// Represents `#[rustc_objc_class]` + ObjcClass { classname: Symbol, span: Span }, + + /// Represents `#[rustc_objc_selector]` + ObjcSelector { methname: Symbol, span: Span }, + /// Represents `#[optimize(size|speed)]` Optimize(OptimizeAttr, Span), diff --git a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs index 55521c15854..cb4feeb05f1 100644 --- a/compiler/rustc_hir/src/attrs/encode_cross_crate.rs +++ b/compiler/rustc_hir/src/attrs/encode_cross_crate.rs @@ -69,6 +69,8 @@ impl AttributeKind { NoMangle(..) => Yes, // Needed for rustdoc NoStd(..) => No, NonExhaustive(..) => Yes, // Needed for rustdoc + ObjcClass { .. } => No, + ObjcSelector { .. } => No, Optimize(..) => No, ParenSugar(..) => No, PassByValue(..) => Yes, diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 67d2f15d414..2e099a97b65 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -370,7 +370,6 @@ language_item_table! { CoercePointeeValidated, sym::coerce_pointee_validated, coerce_pointee_validated_trait, Target::Trait, GenericRequirement::Exact(0); ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0); - UnsizedConstParamTy, sym::unsized_const_param_ty, unsized_const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0); Poll, sym::Poll, poll, Target::Enum, GenericRequirement::None; PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None; diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 63d0f400aef..e70d5505aae 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -70,6 +70,7 @@ pub mod intrinsic; mod region; pub mod wfcheck; +use std::borrow::Cow; use std::num::NonZero; pub use check::{check_abi, check_custom_abi}; @@ -86,7 +87,7 @@ use rustc_middle::query::Providers; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::print::with_types_for_signature; use rustc_middle::ty::{ - self, GenericArgs, GenericArgsRef, GenericParamDefKind, Ty, TyCtxt, TypingMode, + self, GenericArgs, GenericArgsRef, OutlivesPredicate, Region, Ty, TyCtxt, TypingMode, }; use rustc_middle::{bug, span_bug}; use rustc_session::parse::feature_err; @@ -335,6 +336,7 @@ fn bounds_from_generic_predicates<'tcx>( assoc: ty::AssocItem, ) -> (String, String) { let mut types: FxIndexMap<Ty<'tcx>, Vec<DefId>> = FxIndexMap::default(); + let mut regions: FxIndexMap<Region<'tcx>, Vec<Region<'tcx>>> = FxIndexMap::default(); let mut projections = vec![]; for (predicate, _) in predicates { debug!("predicate {:?}", predicate); @@ -351,20 +353,23 @@ fn bounds_from_generic_predicates<'tcx>( ty::ClauseKind::Projection(projection_pred) => { projections.push(bound_predicate.rebind(projection_pred)); } + ty::ClauseKind::RegionOutlives(OutlivesPredicate(a, b)) => { + regions.entry(a).or_default().push(b); + } _ => {} } } let mut where_clauses = vec![]; let generics = tcx.generics_of(assoc.def_id); - let types_str = generics + let params = generics .own_params .iter() - .filter(|p| matches!(p.kind, GenericParamDefKind::Type { synthetic: false, .. })) - .map(|p| { - // we just checked that it's a type, so the unwrap can't fail - let ty = tcx.mk_param_from_def(p).as_type().unwrap(); - if let Some(bounds) = types.get(&ty) { + .filter(|p| !p.kind.is_synthetic()) + .map(|p| match tcx.mk_param_from_def(p).kind() { + ty::GenericArgKind::Type(ty) => { + let bounds = + types.get(&ty).map(Cow::Borrowed).unwrap_or_else(|| Cow::Owned(Vec::new())); let mut bounds_str = vec![]; for bound in bounds.iter().copied() { let mut projections_str = vec![]; @@ -377,7 +382,11 @@ fn bounds_from_generic_predicates<'tcx>( projections_str.push(format!("{} = {}", name, p.term)); } } - let bound_def_path = tcx.def_path_str(bound); + let bound_def_path = if tcx.is_lang_item(bound, LangItem::MetaSized) { + String::from("?Sized") + } else { + tcx.def_path_str(bound) + }; if projections_str.is_empty() { where_clauses.push(format!("{}: {}", ty, bound_def_path)); } else { @@ -393,8 +402,21 @@ fn bounds_from_generic_predicates<'tcx>( } else { format!("{}: {}", ty, bounds_str.join(" + ")) } - } else { - ty.to_string() + } + ty::GenericArgKind::Const(ct) => { + format!("const {ct}: {}", tcx.type_of(p.def_id).skip_binder()) + } + ty::GenericArgKind::Lifetime(region) => { + if let Some(v) = regions.get(®ion) + && !v.is_empty() + { + format!( + "{region}: {}", + v.into_iter().map(Region::to_string).collect::<Vec<_>>().join(" + ") + ) + } else { + region.to_string() + } } }) .collect::<Vec<_>>(); @@ -409,7 +431,7 @@ fn bounds_from_generic_predicates<'tcx>( } let generics = - if types_str.is_empty() { "".to_string() } else { format!("<{}>", types_str.join(", ")) }; + if params.is_empty() { "".to_string() } else { format!("<{}>", params.join(", ")) }; let where_clauses = if where_clauses.is_empty() { "".to_string() diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs index 2ba7ed46f92..43e6f5fe104 100644 --- a/compiler/rustc_hir_analysis/src/check/region.rs +++ b/compiler/rustc_hir_analysis/src/check/region.rs @@ -467,8 +467,12 @@ fn resolve_local<'tcx>( // A, but the inner rvalues `a()` and `b()` have an extended lifetime // due to rule C. - if let_kind == LetKind::Super { - if let Some(scope) = visitor.extended_super_lets.remove(&pat.unwrap().hir_id.local_id) { + let extend_initializer = match let_kind { + LetKind::Regular => true, + LetKind::Super + if let Some(scope) = + visitor.extended_super_lets.remove(&pat.unwrap().hir_id.local_id) => + { // This expression was lifetime-extended by a parent let binding. E.g. // // let a = { @@ -481,7 +485,10 @@ fn resolve_local<'tcx>( // Processing of `let a` will have already decided to extend the lifetime of this // `super let` to its own var_scope. We use that scope. visitor.cx.var_parent = scope; - } else { + // Extend temporaries to live in the same scope as the parent `let`'s bindings. + true + } + LetKind::Super => { // This `super let` is not subject to lifetime extension from a parent let binding. E.g. // // identity({ super let x = temp(); &x }).method(); @@ -493,10 +500,17 @@ fn resolve_local<'tcx>( if let Some(inner_scope) = visitor.cx.var_parent { (visitor.cx.var_parent, _) = visitor.scope_tree.default_temporary_scope(inner_scope) } + // Don't lifetime-extend child `super let`s or block tail expressions' temporaries in + // the initializer when this `super let` is not itself extended by a parent `let` + // (#145784). Block tail expressions are temporary drop scopes in Editions 2024 and + // later, their temps shouldn't outlive the block in e.g. `f(pin!({ &temp() }))`. + false } - } + }; - if let Some(expr) = init { + if let Some(expr) = init + && extend_initializer + { record_rvalue_scope_if_borrow_expr(visitor, expr, visitor.cx.var_parent); if let Some(pat) = pat { diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs index d33f1f3e12a..0a555c7f6e9 100644 --- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs +++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs @@ -819,17 +819,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &ty::GenericParamDef) -> Result<(), Er let span = tcx.def_span(param.def_id); let def_id = param.def_id.expect_local(); - if tcx.features().unsized_const_params() { - enter_wf_checking_ctxt(tcx, tcx.local_parent(def_id), |wfcx| { - wfcx.register_bound( - ObligationCause::new(span, def_id, ObligationCauseCode::ConstParam(ty)), - wfcx.param_env, - ty, - tcx.require_lang_item(LangItem::UnsizedConstParamTy, span), - ); - Ok(()) - }) - } else if tcx.features().adt_const_params() { + if tcx.features().adt_const_params() { enter_wf_checking_ctxt(tcx, tcx.local_parent(def_id), |wfcx| { wfcx.register_bound( ObligationCause::new(span, def_id, ObligationCauseCode::ConstParam(ty)), @@ -880,7 +870,6 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &ty::GenericParamDef) -> Result<(), Er tcx, tcx.param_env(param.def_id), ty, - LangItem::ConstParamTy, cause, ) { // Can never implement `ConstParamTy`, don't suggest anything. diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs index 32b175611ce..0b9a01d6042 100644 --- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs +++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs @@ -1,7 +1,6 @@ //! Check properties that are required by built-in traits and set //! up data structures required by type-checking/codegen. -use std::assert_matches::assert_matches; use std::collections::BTreeMap; use rustc_data_structures::fx::FxHashSet; @@ -40,10 +39,7 @@ pub(super) fn check_trait<'tcx>( checker.check(lang_items.async_drop_trait(), visit_implementation_of_drop)?; checker.check(lang_items.copy_trait(), visit_implementation_of_copy)?; checker.check(lang_items.const_param_ty_trait(), |checker| { - visit_implementation_of_const_param_ty(checker, LangItem::ConstParamTy) - })?; - checker.check(lang_items.unsized_const_param_ty_trait(), |checker| { - visit_implementation_of_const_param_ty(checker, LangItem::UnsizedConstParamTy) + visit_implementation_of_const_param_ty(checker) })?; checker.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)?; checker @@ -138,12 +134,7 @@ fn visit_implementation_of_copy(checker: &Checker<'_>) -> Result<(), ErrorGuaran } } -fn visit_implementation_of_const_param_ty( - checker: &Checker<'_>, - kind: LangItem, -) -> Result<(), ErrorGuaranteed> { - assert_matches!(kind, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy); - +fn visit_implementation_of_const_param_ty(checker: &Checker<'_>) -> Result<(), ErrorGuaranteed> { let tcx = checker.tcx; let header = checker.impl_header; let impl_did = checker.impl_def_id; @@ -157,7 +148,7 @@ fn visit_implementation_of_const_param_ty( } let cause = traits::ObligationCause::misc(DUMMY_SP, impl_did); - match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, kind, cause) { + match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) { Ok(()) => Ok(()), Err(ConstParamTyImplementationError::InfrigingFields(fields)) => { let span = tcx.hir_expect_item(impl_did).expect_impl().self_ty.span; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index 44a6084ebd5..7ca8580e098 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1,3 +1,4 @@ +use std::ops::Deref; use std::{fmt, iter, mem}; use itertools::Itertools; @@ -7,7 +8,7 @@ use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, a_or_an, lis use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::intravisit::Visitor; -use rustc_hir::{ExprKind, HirId, LangItem, Node, QPath}; +use rustc_hir::{Expr, ExprKind, HirId, LangItem, Node, QPath}; use rustc_hir_analysis::check::potentially_plural_count; use rustc_hir_analysis::hir_ty_lowering::{HirTyLowerer, PermitVariants}; use rustc_index::IndexVec; @@ -565,358 +566,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tuple_arguments: TupleArgumentsFlag, ) -> ErrorGuaranteed { // Next, let's construct the error - let (error_span, call_ident, full_call_span, call_name, is_method) = match &call_expr.kind { - hir::ExprKind::Call( - hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. }, - _, - ) => { - if let Res::Def(DefKind::Ctor(of, _), _) = - self.typeck_results.borrow().qpath_res(qpath, *hir_id) - { - let name = match of { - CtorOf::Struct => "struct", - CtorOf::Variant => "enum variant", - }; - (call_span, None, *span, name, false) - } else { - (call_span, None, *span, "function", false) - } - } - hir::ExprKind::Call(hir::Expr { span, .. }, _) => { - (call_span, None, *span, "function", false) - } - hir::ExprKind::MethodCall(path_segment, _, _, span) => { - let ident_span = path_segment.ident.span; - let ident_span = if let Some(args) = path_segment.args { - ident_span.with_hi(args.span_ext.hi()) - } else { - ident_span - }; - (*span, Some(path_segment.ident), ident_span, "method", true) - } - k => span_bug!(call_span, "checking argument types on a non-call: `{:?}`", k), - }; - let args_span = error_span.trim_start(full_call_span).unwrap_or(error_span); - - // Don't print if it has error types or is just plain `_` - fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool { - tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var()) - } - - let tcx = self.tcx; - - // Get the argument span in the context of the call span so that - // suggestions and labels are (more) correct when an arg is a - // macro invocation. - let normalize_span = |span: Span| -> Span { - let normalized_span = span.find_ancestor_inside_same_ctxt(error_span).unwrap_or(span); - // Sometimes macros mess up the spans, so do not normalize the - // arg span to equal the error span, because that's less useful - // than pointing out the arg expr in the wrong context. - if normalized_span.source_equal(error_span) { span } else { normalized_span } - }; - - // Precompute the provided types and spans, since that's all we typically need for below - let provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> = provided_args - .iter() - .map(|expr| { - let ty = self - .typeck_results - .borrow() - .expr_ty_adjusted_opt(*expr) - .unwrap_or_else(|| Ty::new_misc_error(tcx)); - (self.resolve_vars_if_possible(ty), normalize_span(expr.span)) - }) - .collect(); - let callee_expr = match &call_expr.peel_blocks().kind { - hir::ExprKind::Call(callee, _) => Some(*callee), - hir::ExprKind::MethodCall(_, receiver, ..) => { - if let Some((DefKind::AssocFn, def_id)) = - self.typeck_results.borrow().type_dependent_def(call_expr.hir_id) - && let Some(assoc) = tcx.opt_associated_item(def_id) - && assoc.is_method() - { - Some(*receiver) - } else { - None - } - } - _ => None, - }; - let callee_ty = callee_expr - .and_then(|callee_expr| self.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr)); - - // Obtain another method on `Self` that have similar name. - let similar_assoc = |call_name: Ident| -> Option<(ty::AssocItem, ty::FnSig<'_>)> { - if let Some(callee_ty) = callee_ty - && let Ok(Some(assoc)) = self.probe_op( - call_name.span, - MethodCall, - Some(call_name), - None, - IsSuggestion(true), - callee_ty.peel_refs(), - callee_expr.unwrap().hir_id, - TraitsInScope, - |mut ctxt| ctxt.probe_for_similar_candidate(), - ) - && assoc.is_method() - { - let args = self.infcx.fresh_args_for_item(call_name.span, assoc.def_id); - let fn_sig = tcx.fn_sig(assoc.def_id).instantiate(tcx, args); - - self.instantiate_binder_with_fresh_vars( - call_name.span, - BoundRegionConversionTime::FnCall, - fn_sig, - ); - } - None - }; - - let suggest_confusable = |err: &mut Diag<'_>| { - let Some(call_name) = call_ident else { - return; - }; - let Some(callee_ty) = callee_ty else { - return; - }; - let input_types: Vec<Ty<'_>> = provided_arg_tys.iter().map(|(ty, _)| *ty).collect(); - // Check for other methods in the following order - // - methods marked as `rustc_confusables` with the provided arguments - // - methods with the same argument type/count and short levenshtein distance - // - methods marked as `rustc_confusables` (done) - // - methods with short levenshtein distance - - // Look for commonly confusable method names considering arguments. - if let Some(_name) = self.confusable_method_name( - err, - callee_ty.peel_refs(), - call_name, - Some(input_types.clone()), - ) { - return; - } - // Look for method names with short levenshtein distance, considering arguments. - if let Some((assoc, fn_sig)) = similar_assoc(call_name) - && fn_sig.inputs()[1..] - .iter() - .zip(input_types.iter()) - .all(|(expected, found)| self.may_coerce(*expected, *found)) - && fn_sig.inputs()[1..].len() == input_types.len() - { - let assoc_name = assoc.name(); - err.span_suggestion_verbose( - call_name.span, - format!("you might have meant to use `{}`", assoc_name), - assoc_name, - Applicability::MaybeIncorrect, - ); - return; - } - // Look for commonly confusable method names disregarding arguments. - if let Some(_name) = - self.confusable_method_name(err, callee_ty.peel_refs(), call_name, None) - { - return; - } - // Look for similarly named methods with levenshtein distance with the right - // number of arguments. - if let Some((assoc, fn_sig)) = similar_assoc(call_name) - && fn_sig.inputs()[1..].len() == input_types.len() - { - err.span_note( - tcx.def_span(assoc.def_id), - format!( - "there's is a method with similar name `{}`, but the arguments don't match", - assoc.name(), - ), - ); - return; - } - // Fallthrough: look for similarly named methods with levenshtein distance. - if let Some((assoc, _)) = similar_assoc(call_name) { - err.span_note( - tcx.def_span(assoc.def_id), - format!( - "there's is a method with similar name `{}`, but their argument count \ - doesn't match", - assoc.name(), - ), - ); - return; - } - }; - // A "softer" version of the `demand_compatible`, which checks types without persisting them, - // and treats error types differently - // This will allow us to "probe" for other argument orders that would likely have been correct - let check_compatible = |provided_idx: ProvidedIdx, expected_idx: ExpectedIdx| { - if provided_idx.as_usize() == expected_idx.as_usize() { - return compatibility_diagonal[provided_idx].clone(); - } - - let (formal_input_ty, expected_input_ty) = formal_and_expected_inputs[expected_idx]; - // If either is an error type, we defy the usual convention and consider them to *not* be - // coercible. This prevents our error message heuristic from trying to pass errors into - // every argument. - if (formal_input_ty, expected_input_ty).references_error() { - return Compatibility::Incompatible(None); - } - let (arg_ty, arg_span) = provided_arg_tys[provided_idx]; - - let expectation = Expectation::rvalue_hint(self, expected_input_ty); - let coerced_ty = expectation.only_has_type(self).unwrap_or(formal_input_ty); - let can_coerce = self.may_coerce(arg_ty, coerced_ty); - if !can_coerce { - return Compatibility::Incompatible(Some(ty::error::TypeError::Sorts( - ty::error::ExpectedFound::new(coerced_ty, arg_ty), - ))); - } - - // Using probe here, since we don't want this subtyping to affect inference. - let subtyping_error = self.probe(|_| { - self.at(&self.misc(arg_span), self.param_env) - .sup(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty) - .err() - }); - - // Same as above: if either the coerce type or the checked type is an error type, - // consider them *not* compatible. - let references_error = (coerced_ty, arg_ty).references_error(); - match (references_error, subtyping_error) { - (false, None) => Compatibility::Compatible, - (_, subtyping_error) => Compatibility::Incompatible(subtyping_error), - } - }; - - let mk_trace = |span, (formal_ty, expected_ty), provided_ty| { - let mismatched_ty = if expected_ty == provided_ty { - // If expected == provided, then we must have failed to sup - // the formal type. Avoid printing out "expected Ty, found Ty" - // in that case. - formal_ty - } else { - expected_ty - }; - TypeTrace::types(&self.misc(span), mismatched_ty, provided_ty) - }; - - // The algorithm here is inspired by levenshtein distance and longest common subsequence. - // We'll try to detect 4 different types of mistakes: - // - An extra parameter has been provided that doesn't satisfy *any* of the other inputs - // - An input is missing, which isn't satisfied by *any* of the other arguments - // - Some number of arguments have been provided in the wrong order - // - A type is straight up invalid - - // First, let's find the errors - let (mut errors, matched_inputs) = - ArgMatrix::new(provided_args.len(), formal_and_expected_inputs.len(), check_compatible) - .find_errors(); + let mut fn_call_diag_ctxt = FnCallDiagCtxt::new( + self, + compatibility_diagonal, + formal_and_expected_inputs, + provided_args, + c_variadic, + err_code, + fn_def_id, + call_span, + call_expr, + tuple_arguments, + ); // First, check if we just need to wrap some arguments in a tuple. - if let Some((mismatch_idx, terr)) = - compatibility_diagonal.iter_enumerated().find_map(|(i, c)| { - if let Compatibility::Incompatible(Some(terr)) = c { - Some((i, *terr)) - } else { - None - } - }) - { - // Is the first bad expected argument a tuple? - // Do we have as many extra provided arguments as the tuple's length? - // If so, we might have just forgotten to wrap some args in a tuple. - if let Some(ty::Tuple(tys)) = - formal_and_expected_inputs.get(mismatch_idx.to_expected_idx()).map(|tys| tys.1.kind()) - // If the tuple is unit, we're not actually wrapping any arguments. - && !tys.is_empty() - && provided_arg_tys.len() == formal_and_expected_inputs.len() - 1 + tys.len() - { - // Wrap up the N provided arguments starting at this position in a tuple. - let provided_args_to_tuple = &provided_arg_tys[mismatch_idx..]; - let (provided_args_to_tuple, provided_args_after_tuple) = - provided_args_to_tuple.split_at(tys.len()); - let provided_as_tuple = - Ty::new_tup_from_iter(tcx, provided_args_to_tuple.iter().map(|&(ty, _)| ty)); - - let mut satisfied = true; - // Check if the newly wrapped tuple + rest of the arguments are compatible. - for ((_, expected_ty), provided_ty) in std::iter::zip( - formal_and_expected_inputs[mismatch_idx.to_expected_idx()..].iter(), - [provided_as_tuple] - .into_iter() - .chain(provided_args_after_tuple.iter().map(|&(ty, _)| ty)), - ) { - if !self.may_coerce(provided_ty, *expected_ty) { - satisfied = false; - break; - } - } + if let Some(err) = fn_call_diag_ctxt.check_wrap_args_in_tuple() { + return err; + } - // If they're compatible, suggest wrapping in an arg, and we're done! - // Take some care with spans, so we don't suggest wrapping a macro's - // innards in parenthesis, for example. - if satisfied - && let &[(_, hi @ lo)] | &[(_, lo), .., (_, hi)] = provided_args_to_tuple - { - let mut err; - if tys.len() == 1 { - // A tuple wrap suggestion actually occurs within, - // so don't do anything special here. - err = self.err_ctxt().report_and_explain_type_error( - mk_trace( - lo, - formal_and_expected_inputs[mismatch_idx.to_expected_idx()], - provided_arg_tys[mismatch_idx].0, - ), - self.param_env, - terr, - ); - err.span_label( - full_call_span, - format!("arguments to this {call_name} are incorrect"), - ); - } else { - err = self.dcx().struct_span_err( - full_call_span, - format!( - "{call_name} takes {}{} but {} {} supplied", - if c_variadic { "at least " } else { "" }, - potentially_plural_count( - formal_and_expected_inputs.len(), - "argument" - ), - potentially_plural_count(provided_args.len(), "argument"), - pluralize!("was", provided_args.len()) - ), - ); - err.code(err_code.to_owned()); - err.multipart_suggestion_verbose( - "wrap these arguments in parentheses to construct a tuple", - vec![ - (lo.shrink_to_lo(), "(".to_string()), - (hi.shrink_to_hi(), ")".to_string()), - ], - Applicability::MachineApplicable, - ); - }; - self.label_fn_like( - &mut err, - fn_def_id, - callee_ty, - call_expr, - None, - Some(mismatch_idx.as_usize()), - &matched_inputs, - &formal_and_expected_inputs, - is_method, - tuple_arguments, - ); - suggest_confusable(&mut err); - return err.emit(); - } - } + if let Some(fallback_error) = fn_call_diag_ctxt.ensure_has_errors() { + return fallback_error; } // Okay, so here's where it gets complicated in regards to what errors @@ -926,608 +596,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 2) Valid but incorrect arguments // 3) Invalid arguments // - Currently I think this only comes up with `CyclicTy` - // + // We first need to go through, remove those from (3) and emit those // as their own error, particularly since they're error code and // message is special. From what I can tell, we *must* emit these // here (vs somewhere prior to this function) since the arguments // become invalid *because* of how they get used in the function. // It is what it is. - - if errors.is_empty() { - if cfg!(debug_assertions) { - span_bug!(error_span, "expected errors from argument matrix"); - } else { - let mut err = - self.dcx().create_err(errors::ArgMismatchIndeterminate { span: error_span }); - suggest_confusable(&mut err); - return err.emit(); - } + if let Some(err) = fn_call_diag_ctxt.filter_out_invalid_arguments() + && fn_call_diag_ctxt.errors.is_empty() + { + // We're done if we found errors, but we already emitted them. + return err; } - let detect_dotdot = |err: &mut Diag<'_>, ty: Ty<'_>, expr: &hir::Expr<'_>| { - if let ty::Adt(adt, _) = ty.kind() - && self.tcx().is_lang_item(adt.did(), hir::LangItem::RangeFull) - && let hir::ExprKind::Struct( - hir::QPath::LangItem(hir::LangItem::RangeFull, _), - [], - _, - ) = expr.kind - { - // We have `Foo(a, .., c)`, where the user might be trying to use the "rest" syntax - // from default field values, which is not supported on tuples. - let explanation = if self.tcx.features().default_field_values() { - "this is only supported on non-tuple struct literals" - } else if self.tcx.sess.is_nightly_build() { - "this is only supported on non-tuple struct literals when \ - `#![feature(default_field_values)]` is enabled" - } else { - "this is not supported" - }; - let msg = format!( - "you might have meant to use `..` to skip providing a value for \ - expected fields, but {explanation}; it is instead interpreted as a \ - `std::ops::RangeFull` literal", - ); - err.span_help(expr.span, msg); - } - }; + assert!(!fn_call_diag_ctxt.errors.is_empty()); - let mut reported = None; - errors.retain(|error| { - let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = - error - else { - return true; - }; - let (provided_ty, provided_span) = provided_arg_tys[*provided_idx]; - let trace = - mk_trace(provided_span, formal_and_expected_inputs[*expected_idx], provided_ty); - if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) { - let mut err = - self.err_ctxt().report_and_explain_type_error(trace, self.param_env, *e); - suggest_confusable(&mut err); - reported = Some(err.emit()); - return false; - } - true - }); - - // We're done if we found errors, but we already emitted them. - if let Some(reported) = reported - && errors.is_empty() - { - return reported; + // Last special case: if there is only one "Incompatible" error, just emit that + if let Some(err) = fn_call_diag_ctxt.check_single_incompatible() { + return err; } - assert!(!errors.is_empty()); // Okay, now that we've emitted the special errors separately, we // are only left missing/extra/swapped and mismatched arguments, both // can be collated pretty easily if needed. - // Next special case: if there is only one "Incompatible" error, just emit that - if let &[ - Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(err))), - ] = &errors[..] - { - let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; - let (provided_ty, provided_arg_span) = provided_arg_tys[provided_idx]; - let trace = mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty); - let mut err = self.err_ctxt().report_and_explain_type_error(trace, self.param_env, err); - self.emit_coerce_suggestions( - &mut err, - provided_args[provided_idx], - provided_ty, - Expectation::rvalue_hint(self, expected_ty) - .only_has_type(self) - .unwrap_or(formal_ty), - None, - None, - ); - err.span_label(full_call_span, format!("arguments to this {call_name} are incorrect")); - - self.label_generic_mismatches( - &mut err, - fn_def_id, - &matched_inputs, - &provided_arg_tys, - &formal_and_expected_inputs, - is_method, - ); - - if let hir::ExprKind::MethodCall(_, rcvr, _, _) = call_expr.kind - && provided_idx.as_usize() == expected_idx.as_usize() - { - self.note_source_of_type_mismatch_constraint( - &mut err, - rcvr, - crate::demand::TypeMismatchSource::Arg { - call_expr, - incompatible_arg: provided_idx.as_usize(), - }, - ); - } - - self.suggest_ptr_null_mut( - expected_ty, - provided_ty, - provided_args[provided_idx], - &mut err, - ); - - self.suggest_deref_unwrap_or( - &mut err, - callee_ty, - call_ident, - expected_ty, - provided_ty, - provided_args[provided_idx], - is_method, - ); - - // Call out where the function is defined - self.label_fn_like( - &mut err, - fn_def_id, - callee_ty, - call_expr, - Some(expected_ty), - Some(expected_idx.as_usize()), - &matched_inputs, - &formal_and_expected_inputs, - is_method, - tuple_arguments, - ); - suggest_confusable(&mut err); - detect_dotdot(&mut err, provided_ty, provided_args[provided_idx]); - return err.emit(); - } - // Special case, we found an extra argument is provided, which is very common in practice. // but there is a obviously better removing suggestion compared to the current one, // try to find the argument with Error type, if we removed it all the types will become good, // then we will replace the current suggestion. - if let [Error::Extra(provided_idx)] = &errors[..] { - let remove_idx_is_perfect = |idx: usize| -> bool { - let removed_arg_tys = provided_arg_tys - .iter() - .enumerate() - .filter_map(|(j, arg)| if idx == j { None } else { Some(arg) }) - .collect::<IndexVec<ProvidedIdx, _>>(); - std::iter::zip(formal_and_expected_inputs.iter(), removed_arg_tys.iter()).all( - |((expected_ty, _), (provided_ty, _))| { - !provided_ty.references_error() - && self.may_coerce(*provided_ty, *expected_ty) - }, - ) - }; + fn_call_diag_ctxt.maybe_optimize_extra_arg_suggestion(); - if !remove_idx_is_perfect(provided_idx.as_usize()) { - if let Some(i) = (0..provided_args.len()).find(|&i| remove_idx_is_perfect(i)) { - errors = vec![Error::Extra(ProvidedIdx::from_usize(i))]; - } - } - } + let mut err = fn_call_diag_ctxt.initial_final_diagnostic(); + fn_call_diag_ctxt.suggest_confusable(&mut err); - let mut err = if formal_and_expected_inputs.len() == provided_args.len() { - struct_span_code_err!( - self.dcx(), - full_call_span, - E0308, - "arguments to this {} are incorrect", - call_name, - ) - } else { - self.dcx() - .struct_span_err( - full_call_span, - format!( - "this {} takes {}{} but {} {} supplied", - call_name, - if c_variadic { "at least " } else { "" }, - potentially_plural_count(formal_and_expected_inputs.len(), "argument"), - potentially_plural_count(provided_args.len(), "argument"), - pluralize!("was", provided_args.len()) - ), - ) - .with_code(err_code.to_owned()) - }; + // As we encounter issues, keep track of what we want to provide for the suggestion. - suggest_confusable(&mut err); - // As we encounter issues, keep track of what we want to provide for the suggestion - let mut labels = vec![]; - // If there is a single error, we give a specific suggestion; otherwise, we change to - // "did you mean" with the suggested function call - enum SuggestionText { - None, - Provide(bool), - Remove(bool), - Swap, - Reorder, - DidYouMean, - } - let mut suggestion_text = SuggestionText::None; - - let ty_to_snippet = |ty: Ty<'tcx>, expected_idx: ExpectedIdx| { - if ty.is_unit() { - "()".to_string() - } else if ty.is_suggestable(tcx, false) { - format!("/* {ty} */") - } else if let Some(fn_def_id) = fn_def_id - && self.tcx.def_kind(fn_def_id).is_fn_like() - && let self_implicit = - matches!(call_expr.kind, hir::ExprKind::MethodCall(..)) as usize - && let Some(Some(arg)) = - self.tcx.fn_arg_idents(fn_def_id).get(expected_idx.as_usize() + self_implicit) - && arg.name != kw::SelfLower - { - format!("/* {} */", arg.name) - } else { - "/* value */".to_string() - } - }; - - let mut errors = errors.into_iter().peekable(); - let mut only_extras_so_far = errors - .peek() - .is_some_and(|first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0)); - let mut prev_extra_idx = None; - let mut suggestions = vec![]; - while let Some(error) = errors.next() { - only_extras_so_far &= matches!(error, Error::Extra(_)); - - match error { - Error::Invalid(provided_idx, expected_idx, compatibility) => { - let (formal_ty, expected_ty) = formal_and_expected_inputs[expected_idx]; - let (provided_ty, provided_span) = provided_arg_tys[provided_idx]; - if let Compatibility::Incompatible(error) = compatibility { - let trace = mk_trace(provided_span, (formal_ty, expected_ty), provided_ty); - if let Some(e) = error { - self.err_ctxt().note_type_err( - &mut err, - &trace.cause, - None, - Some(self.param_env.and(trace.values)), - e, - true, - None, - ); - } - } + let (mut suggestions, labels, suggestion_text) = + fn_call_diag_ctxt.labels_and_suggestion_text(&mut err); - self.emit_coerce_suggestions( - &mut err, - provided_args[provided_idx], - provided_ty, - Expectation::rvalue_hint(self, expected_ty) - .only_has_type(self) - .unwrap_or(formal_ty), - None, - None, - ); - detect_dotdot(&mut err, provided_ty, provided_args[provided_idx]); - } - Error::Extra(arg_idx) => { - let (provided_ty, provided_span) = provided_arg_tys[arg_idx]; - let provided_ty_name = if !has_error_or_infer([provided_ty]) { - // FIXME: not suggestable, use something else - format!(" of type `{provided_ty}`") - } else { - "".to_string() - }; - let idx = if provided_arg_tys.len() == 1 { - "".to_string() - } else { - format!(" #{}", arg_idx.as_usize() + 1) - }; - labels.push(( - provided_span, - format!("unexpected argument{idx}{provided_ty_name}"), - )); - let mut span = provided_span; - if span.can_be_used_for_suggestions() - && error_span.can_be_used_for_suggestions() - { - if arg_idx.index() > 0 - && let Some((_, prev)) = - provided_arg_tys.get(ProvidedIdx::from_usize(arg_idx.index() - 1)) - { - // Include previous comma - span = prev.shrink_to_hi().to(span); - } - - // Is last argument for deletion in a row starting from the 0-th argument? - // Then delete the next comma, so we are not left with `f(, ...)` - // - // fn f() {} - // - f(0, 1,) - // + f() - let trim_next_comma = match errors.peek() { - Some(Error::Extra(provided_idx)) - if only_extras_so_far - && provided_idx.index() > arg_idx.index() + 1 => - // If the next Error::Extra ("next") doesn't next to current ("current"), - // fn foo(_: (), _: u32) {} - // - foo("current", (), 1u32, "next") - // + foo((), 1u32) - // If the previous error is not a `Error::Extra`, then do not trim the next comma - // - foo((), "current", 42u32, "next") - // + foo((), 42u32) - { - prev_extra_idx.is_none_or(|prev_extra_idx| { - prev_extra_idx + 1 == arg_idx.index() - }) - } - // If no error left, we need to delete the next comma - None if only_extras_so_far => true, - // Not sure if other error type need to be handled as well - _ => false, - }; - - if trim_next_comma { - let next = provided_arg_tys - .get(arg_idx + 1) - .map(|&(_, sp)| sp) - .unwrap_or_else(|| { - // Try to move before `)`. Note that `)` here is not necessarily - // the latin right paren, it could be a Unicode-confusable that - // looks like a `)`, so we must not use `- BytePos(1)` - // manipulations here. - self.tcx().sess.source_map().end_point(call_expr.span) - }); - - // Include next comma - span = span.until(next); - } - - suggestions.push((span, String::new())); - - suggestion_text = match suggestion_text { - SuggestionText::None => SuggestionText::Remove(false), - SuggestionText::Remove(_) => SuggestionText::Remove(true), - _ => SuggestionText::DidYouMean, - }; - prev_extra_idx = Some(arg_idx.index()) - } - detect_dotdot(&mut err, provided_ty, provided_args[arg_idx]); - } - Error::Missing(expected_idx) => { - // If there are multiple missing arguments adjacent to each other, - // then we can provide a single error. - - let mut missing_idxs = vec![expected_idx]; - while let Some(e) = errors.next_if(|e| { - matches!(e, Error::Missing(next_expected_idx) - if *next_expected_idx == *missing_idxs.last().unwrap() + 1) - }) { - match e { - Error::Missing(expected_idx) => missing_idxs.push(expected_idx), - _ => unreachable!( - "control flow ensures that we should always get an `Error::Missing`" - ), - } - } - - // NOTE: Because we might be re-arranging arguments, might have extra - // arguments, etc. it's hard to *really* know where we should provide - // this error label, so as a heuristic, we point to the provided arg, or - // to the call if the missing inputs pass the provided args. - match &missing_idxs[..] { - &[expected_idx] => { - let (_, input_ty) = formal_and_expected_inputs[expected_idx]; - let span = if let Some((_, arg_span)) = - provided_arg_tys.get(expected_idx.to_provided_idx()) - { - *arg_span - } else { - args_span - }; - let rendered = if !has_error_or_infer([input_ty]) { - format!(" of type `{input_ty}`") - } else { - "".to_string() - }; - labels.push(( - span, - format!( - "argument #{}{rendered} is missing", - expected_idx.as_usize() + 1 - ), - )); - - suggestion_text = match suggestion_text { - SuggestionText::None => SuggestionText::Provide(false), - SuggestionText::Provide(_) => SuggestionText::Provide(true), - _ => SuggestionText::DidYouMean, - }; - } - &[first_idx, second_idx] => { - let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; - let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; - let span = if let (Some((_, first_span)), Some((_, second_span))) = ( - provided_arg_tys.get(first_idx.to_provided_idx()), - provided_arg_tys.get(second_idx.to_provided_idx()), - ) { - first_span.to(*second_span) - } else { - args_span - }; - let rendered = - if !has_error_or_infer([first_expected_ty, second_expected_ty]) { - format!( - " of type `{first_expected_ty}` and `{second_expected_ty}`" - ) - } else { - "".to_string() - }; - labels.push((span, format!("two arguments{rendered} are missing"))); - suggestion_text = match suggestion_text { - SuggestionText::None | SuggestionText::Provide(_) => { - SuggestionText::Provide(true) - } - _ => SuggestionText::DidYouMean, - }; - } - &[first_idx, second_idx, third_idx] => { - let (_, first_expected_ty) = formal_and_expected_inputs[first_idx]; - let (_, second_expected_ty) = formal_and_expected_inputs[second_idx]; - let (_, third_expected_ty) = formal_and_expected_inputs[third_idx]; - let span = if let (Some((_, first_span)), Some((_, third_span))) = ( - provided_arg_tys.get(first_idx.to_provided_idx()), - provided_arg_tys.get(third_idx.to_provided_idx()), - ) { - first_span.to(*third_span) - } else { - args_span - }; - let rendered = if !has_error_or_infer([ - first_expected_ty, - second_expected_ty, - third_expected_ty, - ]) { - format!( - " of type `{first_expected_ty}`, `{second_expected_ty}`, and `{third_expected_ty}`" - ) - } else { - "".to_string() - }; - labels.push((span, format!("three arguments{rendered} are missing"))); - suggestion_text = match suggestion_text { - SuggestionText::None | SuggestionText::Provide(_) => { - SuggestionText::Provide(true) - } - _ => SuggestionText::DidYouMean, - }; - } - missing_idxs => { - let first_idx = *missing_idxs.first().unwrap(); - let last_idx = *missing_idxs.last().unwrap(); - // NOTE: Because we might be re-arranging arguments, might have extra arguments, etc. - // It's hard to *really* know where we should provide this error label, so this is a - // decent heuristic - let span = if let (Some((_, first_span)), Some((_, last_span))) = ( - provided_arg_tys.get(first_idx.to_provided_idx()), - provided_arg_tys.get(last_idx.to_provided_idx()), - ) { - first_span.to(*last_span) - } else { - args_span - }; - labels.push((span, "multiple arguments are missing".to_string())); - suggestion_text = match suggestion_text { - SuggestionText::None | SuggestionText::Provide(_) => { - SuggestionText::Provide(true) - } - _ => SuggestionText::DidYouMean, - }; - } - } - } - Error::Swap( - first_provided_idx, - second_provided_idx, - first_expected_idx, - second_expected_idx, - ) => { - let (first_provided_ty, first_span) = provided_arg_tys[first_provided_idx]; - let (_, first_expected_ty) = formal_and_expected_inputs[first_expected_idx]; - let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) { - format!(", found `{first_provided_ty}`") - } else { - String::new() - }; - labels.push(( - first_span, - format!("expected `{first_expected_ty}`{first_provided_ty_name}"), - )); - - let (second_provided_ty, second_span) = provided_arg_tys[second_provided_idx]; - let (_, second_expected_ty) = formal_and_expected_inputs[second_expected_idx]; - let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) { - format!(", found `{second_provided_ty}`") - } else { - String::new() - }; - labels.push(( - second_span, - format!("expected `{second_expected_ty}`{second_provided_ty_name}"), - )); - - suggestion_text = match suggestion_text { - SuggestionText::None => SuggestionText::Swap, - _ => SuggestionText::DidYouMean, - }; - } - Error::Permutation(args) => { - for (dst_arg, dest_input) in args { - let (_, expected_ty) = formal_and_expected_inputs[dst_arg]; - let (provided_ty, provided_span) = provided_arg_tys[dest_input]; - let provided_ty_name = if !has_error_or_infer([provided_ty]) { - format!(", found `{provided_ty}`") - } else { - String::new() - }; - labels.push(( - provided_span, - format!("expected `{expected_ty}`{provided_ty_name}"), - )); - } - - suggestion_text = match suggestion_text { - SuggestionText::None => SuggestionText::Reorder, - _ => SuggestionText::DidYouMean, - }; - } - } - } - - self.label_generic_mismatches( - &mut err, - fn_def_id, - &matched_inputs, - &provided_arg_tys, - &formal_and_expected_inputs, - is_method, - ); - - // Incorporate the argument changes in the removal suggestion. - // When a type is *missing*, and the rest are additional, we want to suggest these with a - // multipart suggestion, but in order to do so we need to figure out *where* the arg that - // was provided but had the wrong type should go, because when looking at `expected_idx` - // that is the position in the argument list in the definition, while `provided_idx` will - // not be present. So we have to look at what the *last* provided position was, and point - // one after to suggest the replacement. FIXME(estebank): This is hacky, and there's - // probably a better more involved change we can make to make this work. - // For example, if we have - // ``` - // fn foo(i32, &'static str) {} - // foo((), (), ()); - // ``` - // what should be suggested is - // ``` - // foo(/* i32 */, /* &str */); - // ``` - // which includes the replacement of the first two `()` for the correct type, and the - // removal of the last `()`. - let mut prev = -1; - for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { - // We want to point not at the *current* argument expression index, but rather at the - // index position where it *should have been*, which is *after* the previous one. - if let Some(provided_idx) = provided_idx { - prev = provided_idx.index() as i64; - continue; - } - let idx = ProvidedIdx::from_usize((prev + 1) as usize); - if let Some((_, arg_span)) = provided_arg_tys.get(idx) { - prev += 1; - // There is a type that was *not* found anywhere, so it isn't a move, but a - // replacement and we look at what type it should have been. This will allow us - // To suggest a multipart suggestion when encountering `foo(1, "")` where the def - // was `fn foo(())`. - let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; - suggestions.push((*arg_span, ty_to_snippet(expected_ty, expected_idx))); - } - } + fn_call_diag_ctxt.label_generic_mismatches(&mut err); + fn_call_diag_ctxt.append_arguments_changes(&mut suggestions); // If we have less than 5 things to say, it would be useful to call out exactly what's wrong if labels.len() <= 5 { @@ -1537,113 +646,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // Call out where the function is defined - self.label_fn_like( + fn_call_diag_ctxt.label_fn_like( &mut err, fn_def_id, - callee_ty, + fn_call_diag_ctxt.callee_ty, call_expr, None, None, - &matched_inputs, - &formal_and_expected_inputs, - is_method, + &fn_call_diag_ctxt.matched_inputs, + &fn_call_diag_ctxt.formal_and_expected_inputs, + fn_call_diag_ctxt.call_metadata.is_method, tuple_arguments, ); // And add a suggestion block for all of the parameters - let suggestion_text = match suggestion_text { - SuggestionText::None => None, - SuggestionText::Provide(plural) => { - Some(format!("provide the argument{}", if plural { "s" } else { "" })) - } - SuggestionText::Remove(plural) => { - err.multipart_suggestion_verbose( - format!("remove the extra argument{}", if plural { "s" } else { "" }), - suggestions, - Applicability::HasPlaceholders, - ); - None - } - SuggestionText::Swap => Some("swap these arguments".to_string()), - SuggestionText::Reorder => Some("reorder these arguments".to_string()), - SuggestionText::DidYouMean => Some("did you mean".to_string()), - }; - if let Some(suggestion_text) = suggestion_text - && !full_call_span.in_external_macro(self.sess().source_map()) + if let Some(suggestion_message) = + FnCallDiagCtxt::format_suggestion_text(&mut err, suggestions, suggestion_text) + && !fn_call_diag_ctxt.call_is_in_macro() { - let source_map = self.sess().source_map(); - let suggestion_span = if let Some(args_span) = error_span.trim_start(full_call_span) { - // Span of the braces, e.g. `(a, b, c)`. - args_span - } else { - // The arg span of a function call that wasn't even given braces - // like what might happen with delegation reuse. - // e.g. `reuse HasSelf::method;` should suggest `reuse HasSelf::method($args);`. - full_call_span.shrink_to_hi() - }; - - // Controls how the arguments should be listed in the suggestion. - enum ArgumentsFormatting { - SingleLine, - Multiline { fallback_indent: String, brace_indent: String }, - } - let arguments_formatting = { - let mut provided_inputs = matched_inputs.iter().filter_map(|a| *a); - if let Some(brace_indent) = source_map.indentation_before(suggestion_span) - && let Some(first_idx) = provided_inputs.by_ref().next() - && let Some(last_idx) = provided_inputs.by_ref().next() - && let (_, first_span) = provided_arg_tys[first_idx] - && let (_, last_span) = provided_arg_tys[last_idx] - && source_map.is_multiline(first_span.to(last_span)) - && let Some(fallback_indent) = source_map.indentation_before(first_span) - { - ArgumentsFormatting::Multiline { fallback_indent, brace_indent } - } else { - ArgumentsFormatting::SingleLine - } - }; + let (suggestion_span, suggestion_code) = fn_call_diag_ctxt.suggestion_code(); - let mut suggestion = "(".to_owned(); - let mut needs_comma = false; - for (expected_idx, provided_idx) in matched_inputs.iter_enumerated() { - if needs_comma { - suggestion += ","; - } - match &arguments_formatting { - ArgumentsFormatting::SingleLine if needs_comma => suggestion += " ", - ArgumentsFormatting::SingleLine => {} - ArgumentsFormatting::Multiline { .. } => suggestion += "\n", - } - needs_comma = true; - let (suggestion_span, suggestion_text) = if let Some(provided_idx) = provided_idx - && let (_, provided_span) = provided_arg_tys[*provided_idx] - && let Ok(arg_text) = source_map.span_to_snippet(provided_span) - { - (Some(provided_span), arg_text) - } else { - // Propose a placeholder of the correct type - let (_, expected_ty) = formal_and_expected_inputs[expected_idx]; - (None, ty_to_snippet(expected_ty, expected_idx)) - }; - if let ArgumentsFormatting::Multiline { fallback_indent, .. } = - &arguments_formatting - { - let indent = suggestion_span - .and_then(|span| source_map.indentation_before(span)) - .unwrap_or_else(|| fallback_indent.clone()); - suggestion += &indent; - } - suggestion += &suggestion_text; - } - if let ArgumentsFormatting::Multiline { brace_indent, .. } = arguments_formatting { - suggestion += ",\n"; - suggestion += &brace_indent; - } - suggestion += ")"; err.span_suggestion_verbose( suggestion_span, - suggestion_text, - suggestion, + suggestion_message, + suggestion_code, Applicability::HasPlaceholders, ); } @@ -2836,3 +1862,1333 @@ impl FnParam<'_> { D(*self, idx) } } + +struct FnCallDiagCtxt<'a, 'b, 'tcx> { + arg_matching_ctxt: ArgMatchingCtxt<'a, 'b, 'tcx>, + errors: Vec<Error<'tcx>>, + matched_inputs: IndexVec<ExpectedIdx, Option<ProvidedIdx>>, +} + +impl<'a, 'b, 'tcx> Deref for FnCallDiagCtxt<'a, 'b, 'tcx> { + type Target = ArgMatchingCtxt<'a, 'b, 'tcx>; + + fn deref(&self) -> &Self::Target { + &self.arg_matching_ctxt + } +} + +// Controls how the arguments should be listed in the suggestion. +enum ArgumentsFormatting { + SingleLine, + Multiline { fallback_indent: String, brace_indent: String }, +} + +impl<'a, 'b, 'tcx> FnCallDiagCtxt<'a, 'b, 'tcx> { + fn new( + arg: &'a FnCtxt<'b, 'tcx>, + compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>, + formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, + provided_args: IndexVec<ProvidedIdx, &'tcx Expr<'tcx>>, + c_variadic: bool, + err_code: ErrCode, + fn_def_id: Option<DefId>, + call_span: Span, + call_expr: &'tcx Expr<'tcx>, + tuple_arguments: TupleArgumentsFlag, + ) -> Self { + let arg_matching_ctxt = ArgMatchingCtxt::new( + arg, + compatibility_diagonal, + formal_and_expected_inputs, + provided_args, + c_variadic, + err_code, + fn_def_id, + call_span, + call_expr, + tuple_arguments, + ); + + // The algorithm here is inspired by levenshtein distance and longest common subsequence. + // We'll try to detect 4 different types of mistakes: + // - An extra parameter has been provided that doesn't satisfy *any* of the other inputs + // - An input is missing, which isn't satisfied by *any* of the other arguments + // - Some number of arguments have been provided in the wrong order + // - A type is straight up invalid + let (errors, matched_inputs) = ArgMatrix::new( + arg_matching_ctxt.provided_args.len(), + arg_matching_ctxt.formal_and_expected_inputs.len(), + |provided, expected| arg_matching_ctxt.check_compatible(provided, expected), + ) + .find_errors(); + + FnCallDiagCtxt { arg_matching_ctxt, errors, matched_inputs } + } + + fn check_wrap_args_in_tuple(&self) -> Option<ErrorGuaranteed> { + if let Some((mismatch_idx, terr)) = self.first_incompatible_error() { + // Is the first bad expected argument a tuple? + // Do we have as many extra provided arguments as the tuple's length? + // If so, we might have just forgotten to wrap some args in a tuple. + if let Some(ty::Tuple(tys)) = + self.formal_and_expected_inputs.get(mismatch_idx.to_expected_idx()).map(|tys| tys.1.kind()) + // If the tuple is unit, we're not actually wrapping any arguments. + && !tys.is_empty() + && self.provided_arg_tys.len() == self.formal_and_expected_inputs.len() - 1 + tys.len() + { + // Wrap up the N provided arguments starting at this position in a tuple. + let provided_args_to_tuple = &self.provided_arg_tys[mismatch_idx..]; + let (provided_args_to_tuple, provided_args_after_tuple) = + provided_args_to_tuple.split_at(tys.len()); + let provided_as_tuple = Ty::new_tup_from_iter( + self.tcx, + provided_args_to_tuple.iter().map(|&(ty, _)| ty), + ); + + let mut satisfied = true; + // Check if the newly wrapped tuple + rest of the arguments are compatible. + for ((_, expected_ty), provided_ty) in std::iter::zip( + self.formal_and_expected_inputs[mismatch_idx.to_expected_idx()..].iter(), + [provided_as_tuple] + .into_iter() + .chain(provided_args_after_tuple.iter().map(|&(ty, _)| ty)), + ) { + if !self.may_coerce(provided_ty, *expected_ty) { + satisfied = false; + break; + } + } + + // If they're compatible, suggest wrapping in an arg, and we're done! + // Take some care with spans, so we don't suggest wrapping a macro's + // innards in parenthesis, for example. + if satisfied + && let &[(_, hi @ lo)] | &[(_, lo), .., (_, hi)] = provided_args_to_tuple + { + let mut err; + if tys.len() == 1 { + // A tuple wrap suggestion actually occurs within, + // so don't do anything special here. + err = self.err_ctxt().report_and_explain_type_error( + self.arg_matching_ctxt.args_ctxt.call_ctxt.mk_trace( + lo, + self.formal_and_expected_inputs[mismatch_idx.to_expected_idx()], + self.provided_arg_tys[mismatch_idx].0, + ), + self.param_env, + terr, + ); + let call_name = self.call_metadata.call_name; + err.span_label( + self.call_metadata.full_call_span, + format!("arguments to this {call_name} are incorrect"), + ); + } else { + let call_name = self.call_metadata.call_name; + err = self.dcx().struct_span_err( + self.arg_matching_ctxt.args_ctxt.call_metadata.full_call_span, + format!( + "{call_name} takes {}{} but {} {} supplied", + if self.c_variadic { "at least " } else { "" }, + potentially_plural_count( + self.formal_and_expected_inputs.len(), + "argument" + ), + potentially_plural_count(self.provided_args.len(), "argument"), + pluralize!("was", self.provided_args.len()) + ), + ); + err.code(self.err_code.to_owned()); + err.multipart_suggestion_verbose( + "wrap these arguments in parentheses to construct a tuple", + vec![ + (lo.shrink_to_lo(), "(".to_string()), + (hi.shrink_to_hi(), ")".to_string()), + ], + Applicability::MachineApplicable, + ); + }; + self.arg_matching_ctxt.args_ctxt.call_ctxt.fn_ctxt.label_fn_like( + &mut err, + self.fn_def_id, + self.callee_ty, + self.call_expr, + None, + Some(mismatch_idx.as_usize()), + &self.matched_inputs, + &self.formal_and_expected_inputs, + self.call_metadata.is_method, + self.tuple_arguments, + ); + self.suggest_confusable(&mut err); + Some(err.emit()) + } else { + None + } + } else { + None + } + } else { + None + } + } + + fn ensure_has_errors(&self) -> Option<ErrorGuaranteed> { + if self.errors.is_empty() { + if cfg!(debug_assertions) { + span_bug!(self.call_metadata.error_span, "expected errors from argument matrix"); + } else { + let mut err = self.dcx().create_err(errors::ArgMismatchIndeterminate { + span: self.call_metadata.error_span, + }); + self.arg_matching_ctxt.suggest_confusable(&mut err); + return Some(err.emit()); + } + } + + None + } + + fn detect_dotdot(&self, err: &mut Diag<'_>, ty: Ty<'tcx>, expr: &hir::Expr<'tcx>) { + if let ty::Adt(adt, _) = ty.kind() + && self.tcx().is_lang_item(adt.did(), hir::LangItem::RangeFull) + && let hir::ExprKind::Struct(hir::QPath::LangItem(hir::LangItem::RangeFull, _), [], _) = + expr.kind + { + // We have `Foo(a, .., c)`, where the user might be trying to use the "rest" syntax + // from default field values, which is not supported on tuples. + let explanation = if self.tcx.features().default_field_values() { + "this is only supported on non-tuple struct literals" + } else if self.tcx.sess.is_nightly_build() { + "this is only supported on non-tuple struct literals when \ + `#![feature(default_field_values)]` is enabled" + } else { + "this is not supported" + }; + let msg = format!( + "you might have meant to use `..` to skip providing a value for \ + expected fields, but {explanation}; it is instead interpreted as a \ + `std::ops::RangeFull` literal", + ); + err.span_help(expr.span, msg); + } + } + + fn filter_out_invalid_arguments(&mut self) -> Option<ErrorGuaranteed> { + let mut reported = None; + + self.errors.retain(|error| { + let Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(e))) = + error + else { + return true; + }; + let (provided_ty, provided_span) = + self.arg_matching_ctxt.provided_arg_tys[*provided_idx]; + let trace = self.arg_matching_ctxt.mk_trace( + provided_span, + self.arg_matching_ctxt.formal_and_expected_inputs[*expected_idx], + provided_ty, + ); + if !matches!(trace.cause.as_failure_code(*e), FailureCode::Error0308) { + let mut err = self.arg_matching_ctxt.err_ctxt().report_and_explain_type_error( + trace, + self.arg_matching_ctxt.param_env, + *e, + ); + self.arg_matching_ctxt.suggest_confusable(&mut err); + reported = Some(err.emit()); + return false; + } + true + }); + + reported + } + + fn check_single_incompatible(&self) -> Option<ErrorGuaranteed> { + if let &[ + Error::Invalid(provided_idx, expected_idx, Compatibility::Incompatible(Some(err))), + ] = &self.errors[..] + { + let (formal_ty, expected_ty) = self.formal_and_expected_inputs[expected_idx]; + let (provided_ty, provided_arg_span) = self.provided_arg_tys[provided_idx]; + let trace = self.mk_trace(provided_arg_span, (formal_ty, expected_ty), provided_ty); + let mut err = self.err_ctxt().report_and_explain_type_error(trace, self.param_env, err); + self.emit_coerce_suggestions( + &mut err, + self.provided_args[provided_idx], + provided_ty, + Expectation::rvalue_hint(self.fn_ctxt, expected_ty) + .only_has_type(self.fn_ctxt) + .unwrap_or(formal_ty), + None, + None, + ); + let call_name = self.call_metadata.call_name; + err.span_label( + self.call_metadata.full_call_span, + format!("arguments to this {call_name} are incorrect"), + ); + + self.fn_ctxt.label_generic_mismatches( + &mut err, + self.fn_def_id, + &self.matched_inputs, + &self.provided_arg_tys, + &self.formal_and_expected_inputs, + self.call_metadata.is_method, + ); + + if let hir::ExprKind::MethodCall(_, rcvr, _, _) = + self.arg_matching_ctxt.args_ctxt.call_ctxt.call_expr.kind + && provided_idx.as_usize() == expected_idx.as_usize() + { + self.note_source_of_type_mismatch_constraint( + &mut err, + rcvr, + crate::demand::TypeMismatchSource::Arg { + call_expr: self.call_expr, + incompatible_arg: provided_idx.as_usize(), + }, + ); + } + + self.suggest_ptr_null_mut( + expected_ty, + provided_ty, + self.provided_args[provided_idx], + &mut err, + ); + + self.suggest_deref_unwrap_or( + &mut err, + self.callee_ty, + self.call_metadata.call_ident, + expected_ty, + provided_ty, + self.provided_args[provided_idx], + self.call_metadata.is_method, + ); + + // Call out where the function is defined + self.label_fn_like( + &mut err, + self.fn_def_id, + self.callee_ty, + self.call_expr, + Some(expected_ty), + Some(expected_idx.as_usize()), + &self.matched_inputs, + &self.formal_and_expected_inputs, + self.call_metadata.is_method, + self.tuple_arguments, + ); + self.arg_matching_ctxt.suggest_confusable(&mut err); + self.detect_dotdot(&mut err, provided_ty, self.provided_args[provided_idx]); + return Some(err.emit()); + } + + None + } + + fn maybe_optimize_extra_arg_suggestion(&mut self) { + if let [Error::Extra(provided_idx)] = &self.errors[..] { + if !self.remove_idx_is_perfect(provided_idx.as_usize()) { + if let Some(i) = (0..self.args_ctxt.call_ctxt.provided_args.len()) + .find(|&i| self.remove_idx_is_perfect(i)) + { + self.errors = vec![Error::Extra(ProvidedIdx::from_usize(i))]; + } + } + } + } + + fn initial_final_diagnostic(&self) -> Diag<'_> { + if self.formal_and_expected_inputs.len() == self.provided_args.len() { + struct_span_code_err!( + self.dcx(), + self.call_metadata.full_call_span, + E0308, + "arguments to this {} are incorrect", + self.call_metadata.call_name, + ) + } else { + self.arg_matching_ctxt + .dcx() + .struct_span_err( + self.call_metadata.full_call_span, + format!( + "this {} takes {}{} but {} {} supplied", + self.call_metadata.call_name, + if self.c_variadic { "at least " } else { "" }, + potentially_plural_count(self.formal_and_expected_inputs.len(), "argument"), + potentially_plural_count(self.provided_args.len(), "argument"), + pluralize!("was", self.provided_args.len()) + ), + ) + .with_code(self.err_code.to_owned()) + } + } + + fn labels_and_suggestion_text( + &self, + err: &mut Diag<'_>, + ) -> (Vec<(Span, String)>, Vec<(Span, String)>, SuggestionText) { + // Don't print if it has error types or is just plain `_` + fn has_error_or_infer<'tcx>(tys: impl IntoIterator<Item = Ty<'tcx>>) -> bool { + tys.into_iter().any(|ty| ty.references_error() || ty.is_ty_var()) + } + + let mut labels = Vec::new(); + let mut suggestion_text = SuggestionText::None; + + let mut errors = self.errors.iter().peekable(); + let mut only_extras_so_far = errors + .peek() + .is_some_and(|first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0)); + let mut prev_extra_idx = None; + let mut suggestions = vec![]; + while let Some(error) = errors.next() { + only_extras_so_far &= matches!(error, Error::Extra(_)); + + match error { + Error::Invalid(provided_idx, expected_idx, compatibility) => { + let (formal_ty, expected_ty) = + self.arg_matching_ctxt.args_ctxt.call_ctxt.formal_and_expected_inputs + [*expected_idx]; + let (provided_ty, provided_span) = + self.arg_matching_ctxt.provided_arg_tys[*provided_idx]; + if let Compatibility::Incompatible(error) = compatibility { + let trace = self.arg_matching_ctxt.args_ctxt.call_ctxt.mk_trace( + provided_span, + (formal_ty, expected_ty), + provided_ty, + ); + if let Some(e) = error { + self.err_ctxt().note_type_err( + err, + &trace.cause, + None, + Some(self.param_env.and(trace.values)), + *e, + true, + None, + ); + } + } + + self.emit_coerce_suggestions( + err, + self.provided_args[*provided_idx], + provided_ty, + Expectation::rvalue_hint(self.fn_ctxt, expected_ty) + .only_has_type(self.fn_ctxt) + .unwrap_or(formal_ty), + None, + None, + ); + self.detect_dotdot(err, provided_ty, self.provided_args[*provided_idx]); + } + Error::Extra(arg_idx) => { + let (provided_ty, provided_span) = self.provided_arg_tys[*arg_idx]; + let provided_ty_name = if !has_error_or_infer([provided_ty]) { + // FIXME: not suggestable, use something else + format!(" of type `{provided_ty}`") + } else { + "".to_string() + }; + let idx = if self.provided_arg_tys.len() == 1 { + "".to_string() + } else { + format!(" #{}", arg_idx.as_usize() + 1) + }; + labels.push(( + provided_span, + format!("unexpected argument{idx}{provided_ty_name}"), + )); + let mut span = provided_span; + if span.can_be_used_for_suggestions() + && self.call_metadata.error_span.can_be_used_for_suggestions() + { + if arg_idx.index() > 0 + && let Some((_, prev)) = self + .provided_arg_tys + .get(ProvidedIdx::from_usize(arg_idx.index() - 1)) + { + // Include previous comma + span = prev.shrink_to_hi().to(span); + } + + // Is last argument for deletion in a row starting from the 0-th argument? + // Then delete the next comma, so we are not left with `f(, ...)` + // + // fn f() {} + // - f(0, 1,) + // + f() + let trim_next_comma = match errors.peek() { + Some(Error::Extra(provided_idx)) + if only_extras_so_far + && provided_idx.index() > arg_idx.index() + 1 => + // If the next Error::Extra ("next") doesn't next to current ("current"), + // fn foo(_: (), _: u32) {} + // - foo("current", (), 1u32, "next") + // + foo((), 1u32) + // If the previous error is not a `Error::Extra`, then do not trim the next comma + // - foo((), "current", 42u32, "next") + // + foo((), 42u32) + { + prev_extra_idx.is_none_or(|prev_extra_idx| { + prev_extra_idx + 1 == arg_idx.index() + }) + } + // If no error left, we need to delete the next comma + None if only_extras_so_far => true, + // Not sure if other error type need to be handled as well + _ => false, + }; + + if trim_next_comma { + let next = self + .provided_arg_tys + .get(*arg_idx + 1) + .map(|&(_, sp)| sp) + .unwrap_or_else(|| { + // Try to move before `)`. Note that `)` here is not necessarily + // the latin right paren, it could be a Unicode-confusable that + // looks like a `)`, so we must not use `- BytePos(1)` + // manipulations here. + self.arg_matching_ctxt + .tcx() + .sess + .source_map() + .end_point(self.call_expr.span) + }); + + // Include next comma + span = span.until(next); + } + + suggestions.push((span, String::new())); + + suggestion_text = match suggestion_text { + SuggestionText::None => SuggestionText::Remove(false), + SuggestionText::Remove(_) => SuggestionText::Remove(true), + _ => SuggestionText::DidYouMean, + }; + prev_extra_idx = Some(arg_idx.index()) + } + self.detect_dotdot(err, provided_ty, self.provided_args[*arg_idx]); + } + Error::Missing(expected_idx) => { + // If there are multiple missing arguments adjacent to each other, + // then we can provide a single error. + + let mut missing_idxs = vec![*expected_idx]; + while let Some(e) = errors.next_if(|e| { + matches!(e, Error::Missing(next_expected_idx) + if *next_expected_idx == *missing_idxs.last().unwrap() + 1) + }) { + match e { + Error::Missing(expected_idx) => missing_idxs.push(*expected_idx), + _ => unreachable!( + "control flow ensures that we should always get an `Error::Missing`" + ), + } + } + + // NOTE: Because we might be re-arranging arguments, might have extra + // arguments, etc. it's hard to *really* know where we should provide + // this error label, so as a heuristic, we point to the provided arg, or + // to the call if the missing inputs pass the provided args. + match &missing_idxs[..] { + &[expected_idx] => { + let (_, input_ty) = self.formal_and_expected_inputs[expected_idx]; + let span = if let Some((_, arg_span)) = + self.provided_arg_tys.get(expected_idx.to_provided_idx()) + { + *arg_span + } else { + self.args_span + }; + let rendered = if !has_error_or_infer([input_ty]) { + format!(" of type `{input_ty}`") + } else { + "".to_string() + }; + labels.push(( + span, + format!( + "argument #{}{rendered} is missing", + expected_idx.as_usize() + 1 + ), + )); + + suggestion_text = match suggestion_text { + SuggestionText::None => SuggestionText::Provide(false), + SuggestionText::Provide(_) => SuggestionText::Provide(true), + _ => SuggestionText::DidYouMean, + }; + } + &[first_idx, second_idx] => { + let (_, first_expected_ty) = self.formal_and_expected_inputs[first_idx]; + let (_, second_expected_ty) = + self.formal_and_expected_inputs[second_idx]; + let span = if let (Some((_, first_span)), Some((_, second_span))) = ( + self.provided_arg_tys.get(first_idx.to_provided_idx()), + self.provided_arg_tys.get(second_idx.to_provided_idx()), + ) { + first_span.to(*second_span) + } else { + self.args_span + }; + let rendered = + if !has_error_or_infer([first_expected_ty, second_expected_ty]) { + format!( + " of type `{first_expected_ty}` and `{second_expected_ty}`" + ) + } else { + "".to_string() + }; + labels.push((span, format!("two arguments{rendered} are missing"))); + suggestion_text = match suggestion_text { + SuggestionText::None | SuggestionText::Provide(_) => { + SuggestionText::Provide(true) + } + _ => SuggestionText::DidYouMean, + }; + } + &[first_idx, second_idx, third_idx] => { + let (_, first_expected_ty) = self.formal_and_expected_inputs[first_idx]; + let (_, second_expected_ty) = + self.formal_and_expected_inputs[second_idx]; + let (_, third_expected_ty) = self.formal_and_expected_inputs[third_idx]; + let span = if let (Some((_, first_span)), Some((_, third_span))) = ( + self.provided_arg_tys.get(first_idx.to_provided_idx()), + self.provided_arg_tys.get(third_idx.to_provided_idx()), + ) { + first_span.to(*third_span) + } else { + self.args_span + }; + let rendered = if !has_error_or_infer([ + first_expected_ty, + second_expected_ty, + third_expected_ty, + ]) { + format!( + " of type `{first_expected_ty}`, `{second_expected_ty}`, and `{third_expected_ty}`" + ) + } else { + "".to_string() + }; + labels.push((span, format!("three arguments{rendered} are missing"))); + suggestion_text = match suggestion_text { + SuggestionText::None | SuggestionText::Provide(_) => { + SuggestionText::Provide(true) + } + _ => SuggestionText::DidYouMean, + }; + } + missing_idxs => { + let first_idx = *missing_idxs.first().unwrap(); + let last_idx = *missing_idxs.last().unwrap(); + // NOTE: Because we might be re-arranging arguments, might have extra arguments, etc. + // It's hard to *really* know where we should provide this error label, so this is a + // decent heuristic + let span = if let (Some((_, first_span)), Some((_, last_span))) = ( + self.provided_arg_tys.get(first_idx.to_provided_idx()), + self.provided_arg_tys.get(last_idx.to_provided_idx()), + ) { + first_span.to(*last_span) + } else { + self.args_span + }; + labels.push((span, "multiple arguments are missing".to_string())); + suggestion_text = match suggestion_text { + SuggestionText::None | SuggestionText::Provide(_) => { + SuggestionText::Provide(true) + } + _ => SuggestionText::DidYouMean, + }; + } + } + } + Error::Swap( + first_provided_idx, + second_provided_idx, + first_expected_idx, + second_expected_idx, + ) => { + let (first_provided_ty, first_span) = + self.provided_arg_tys[*first_provided_idx]; + let (_, first_expected_ty) = + self.formal_and_expected_inputs[*first_expected_idx]; + let first_provided_ty_name = if !has_error_or_infer([first_provided_ty]) { + format!(", found `{first_provided_ty}`") + } else { + String::new() + }; + labels.push(( + first_span, + format!("expected `{first_expected_ty}`{first_provided_ty_name}"), + )); + + let (second_provided_ty, second_span) = + self.provided_arg_tys[*second_provided_idx]; + let (_, second_expected_ty) = + self.formal_and_expected_inputs[*second_expected_idx]; + let second_provided_ty_name = if !has_error_or_infer([second_provided_ty]) { + format!(", found `{second_provided_ty}`") + } else { + String::new() + }; + labels.push(( + second_span, + format!("expected `{second_expected_ty}`{second_provided_ty_name}"), + )); + + suggestion_text = match suggestion_text { + SuggestionText::None => SuggestionText::Swap, + _ => SuggestionText::DidYouMean, + }; + } + Error::Permutation(args) => { + for (dst_arg, dest_input) in args { + let (_, expected_ty) = self.formal_and_expected_inputs[*dst_arg]; + let (provided_ty, provided_span) = self.provided_arg_tys[*dest_input]; + let provided_ty_name = if !has_error_or_infer([provided_ty]) { + format!(", found `{provided_ty}`") + } else { + String::new() + }; + labels.push(( + provided_span, + format!("expected `{expected_ty}`{provided_ty_name}"), + )); + } + + suggestion_text = match suggestion_text { + SuggestionText::None => SuggestionText::Reorder, + _ => SuggestionText::DidYouMean, + }; + } + } + } + + (suggestions, labels, suggestion_text) + } + + fn label_generic_mismatches(&self, err: &mut Diag<'b>) { + self.fn_ctxt.label_generic_mismatches( + err, + self.fn_def_id, + &self.matched_inputs, + &self.provided_arg_tys, + &self.formal_and_expected_inputs, + self.call_metadata.is_method, + ); + } + + /// Incorporate the argument changes in the removal suggestion. + /// + /// When a type is *missing*, and the rest are additional, we want to suggest these with a + /// multipart suggestion, but in order to do so we need to figure out *where* the arg that + /// was provided but had the wrong type should go, because when looking at `expected_idx` + /// that is the position in the argument list in the definition, while `provided_idx` will + /// not be present. So we have to look at what the *last* provided position was, and point + /// one after to suggest the replacement. + fn append_arguments_changes(&self, suggestions: &mut Vec<(Span, String)>) { + // FIXME(estebank): This is hacky, and there's + // probably a better more involved change we can make to make this work. + // For example, if we have + // ``` + // fn foo(i32, &'static str) {} + // foo((), (), ()); + // ``` + // what should be suggested is + // ``` + // foo(/* i32 */, /* &str */); + // ``` + // which includes the replacement of the first two `()` for the correct type, and the + // removal of the last `()`. + + let mut prev = -1; + for (expected_idx, provided_idx) in self.matched_inputs.iter_enumerated() { + // We want to point not at the *current* argument expression index, but rather at the + // index position where it *should have been*, which is *after* the previous one. + if let Some(provided_idx) = provided_idx { + prev = provided_idx.index() as i64; + continue; + } + let idx = ProvidedIdx::from_usize((prev + 1) as usize); + if let Some((_, arg_span)) = self.provided_arg_tys.get(idx) { + prev += 1; + // There is a type that was *not* found anywhere, so it isn't a move, but a + // replacement and we look at what type it should have been. This will allow us + // To suggest a multipart suggestion when encountering `foo(1, "")` where the def + // was `fn foo(())`. + let (_, expected_ty) = self.formal_and_expected_inputs[expected_idx]; + suggestions.push((*arg_span, self.ty_to_snippet(expected_ty, expected_idx))); + } + } + } + + fn format_suggestion_text( + err: &mut Diag<'_>, + suggestions: Vec<(Span, String)>, + suggestion_text: SuggestionText, + ) -> Option<String> { + let suggestion_text = match suggestion_text { + SuggestionText::None => None, + SuggestionText::Provide(plural) => { + Some(format!("provide the argument{}", if plural { "s" } else { "" })) + } + SuggestionText::Remove(plural) => { + err.multipart_suggestion_verbose( + format!("remove the extra argument{}", if plural { "s" } else { "" }), + suggestions, + Applicability::HasPlaceholders, + ); + None + } + SuggestionText::Swap => Some("swap these arguments".to_string()), + SuggestionText::Reorder => Some("reorder these arguments".to_string()), + SuggestionText::DidYouMean => Some("did you mean".to_string()), + }; + suggestion_text + } + + fn arguments_formatting(&self, suggestion_span: Span) -> ArgumentsFormatting { + let source_map = self.sess().source_map(); + let mut provided_inputs = self.matched_inputs.iter().filter_map(|a| *a); + if let Some(brace_indent) = source_map.indentation_before(suggestion_span) + && let Some(first_idx) = provided_inputs.by_ref().next() + && let Some(last_idx) = provided_inputs.by_ref().next() + && let (_, first_span) = self.provided_arg_tys[first_idx] + && let (_, last_span) = self.provided_arg_tys[last_idx] + && source_map.is_multiline(first_span.to(last_span)) + && let Some(fallback_indent) = source_map.indentation_before(first_span) + { + ArgumentsFormatting::Multiline { fallback_indent, brace_indent } + } else { + ArgumentsFormatting::SingleLine + } + } + + fn suggestion_code(&self) -> (Span, String) { + let source_map = self.sess().source_map(); + let suggestion_span = if let Some(args_span) = + self.call_metadata.error_span.trim_start(self.call_metadata.full_call_span) + { + // Span of the braces, e.g. `(a, b, c)`. + args_span + } else { + // The arg span of a function call that wasn't even given braces + // like what might happen with delegation reuse. + // e.g. `reuse HasSelf::method;` should suggest `reuse HasSelf::method($args);`. + self.call_metadata.full_call_span.shrink_to_hi() + }; + + let arguments_formatting = self.arguments_formatting(suggestion_span); + + let mut suggestion = "(".to_owned(); + let mut needs_comma = false; + for (expected_idx, provided_idx) in self.matched_inputs.iter_enumerated() { + if needs_comma { + suggestion += ","; + } + match &arguments_formatting { + ArgumentsFormatting::SingleLine if needs_comma => suggestion += " ", + ArgumentsFormatting::SingleLine => {} + ArgumentsFormatting::Multiline { .. } => suggestion += "\n", + } + needs_comma = true; + let (suggestion_span, suggestion_text) = if let Some(provided_idx) = provided_idx + && let (_, provided_span) = self.provided_arg_tys[*provided_idx] + && let Ok(arg_text) = source_map.span_to_snippet(provided_span) + { + (Some(provided_span), arg_text) + } else { + // Propose a placeholder of the correct type + let (_, expected_ty) = self.formal_and_expected_inputs[expected_idx]; + (None, self.ty_to_snippet(expected_ty, expected_idx)) + }; + if let ArgumentsFormatting::Multiline { fallback_indent, .. } = &arguments_formatting { + let indent = suggestion_span + .and_then(|span| source_map.indentation_before(span)) + .unwrap_or_else(|| fallback_indent.clone()); + suggestion += &indent; + } + suggestion += &suggestion_text; + } + if let ArgumentsFormatting::Multiline { brace_indent, .. } = arguments_formatting { + suggestion += ",\n"; + suggestion += &brace_indent; + } + suggestion += ")"; + + (suggestion_span, suggestion) + } +} + +struct ArgMatchingCtxt<'a, 'b, 'tcx> { + args_ctxt: ArgsCtxt<'a, 'b, 'tcx>, + provided_arg_tys: IndexVec<ProvidedIdx, (Ty<'tcx>, Span)>, +} + +impl<'a, 'b, 'tcx> Deref for ArgMatchingCtxt<'a, 'b, 'tcx> { + type Target = ArgsCtxt<'a, 'b, 'tcx>; + + fn deref(&self) -> &Self::Target { + &self.args_ctxt + } +} + +impl<'a, 'b, 'tcx> ArgMatchingCtxt<'a, 'b, 'tcx> { + fn new( + arg: &'a FnCtxt<'b, 'tcx>, + compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>, + formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, + provided_args: IndexVec<ProvidedIdx, &'tcx Expr<'tcx>>, + c_variadic: bool, + err_code: ErrCode, + fn_def_id: Option<DefId>, + call_span: Span, + call_expr: &'tcx Expr<'tcx>, + tuple_arguments: TupleArgumentsFlag, + ) -> Self { + let args_ctxt = ArgsCtxt::new( + arg, + compatibility_diagonal, + formal_and_expected_inputs, + provided_args, + c_variadic, + err_code, + fn_def_id, + call_span, + call_expr, + tuple_arguments, + ); + let provided_arg_tys = args_ctxt.provided_arg_tys(); + + ArgMatchingCtxt { args_ctxt, provided_arg_tys } + } + + fn suggest_confusable(&self, err: &mut Diag<'_>) { + let Some(call_name) = self.call_metadata.call_ident else { + return; + }; + let Some(callee_ty) = self.callee_ty else { + return; + }; + let input_types: Vec<Ty<'_>> = self.provided_arg_tys.iter().map(|(ty, _)| *ty).collect(); + + // Check for other methods in the following order + // - methods marked as `rustc_confusables` with the provided arguments + // - methods with the same argument type/count and short levenshtein distance + // - methods marked as `rustc_confusables` (done) + // - methods with short levenshtein distance + + // Look for commonly confusable method names considering arguments. + if let Some(_name) = self.confusable_method_name( + err, + callee_ty.peel_refs(), + call_name, + Some(input_types.clone()), + ) { + return; + } + // Look for method names with short levenshtein distance, considering arguments. + if let Some((assoc, fn_sig)) = self.similar_assoc(call_name) + && fn_sig.inputs()[1..] + .iter() + .zip(input_types.iter()) + .all(|(expected, found)| self.may_coerce(*expected, *found)) + && fn_sig.inputs()[1..].len() == input_types.len() + { + let assoc_name = assoc.name(); + err.span_suggestion_verbose( + call_name.span, + format!("you might have meant to use `{}`", assoc_name), + assoc_name, + Applicability::MaybeIncorrect, + ); + return; + } + } + + /// A "softer" version of the `demand_compatible`, which checks types without persisting them, + /// and treats error types differently + /// This will allow us to "probe" for other argument orders that would likely have been correct + fn check_compatible( + &self, + provided_idx: ProvidedIdx, + expected_idx: ExpectedIdx, + ) -> Compatibility<'tcx> { + if provided_idx.as_usize() == expected_idx.as_usize() { + return self.compatibility_diagonal[provided_idx].clone(); + } + + let (formal_input_ty, expected_input_ty) = self.formal_and_expected_inputs[expected_idx]; + // If either is an error type, we defy the usual convention and consider them to *not* be + // coercible. This prevents our error message heuristic from trying to pass errors into + // every argument. + if (formal_input_ty, expected_input_ty).references_error() { + return Compatibility::Incompatible(None); + } + + let (arg_ty, arg_span) = self.provided_arg_tys[provided_idx]; + + let expectation = Expectation::rvalue_hint(self.fn_ctxt, expected_input_ty); + let coerced_ty = expectation.only_has_type(self.fn_ctxt).unwrap_or(formal_input_ty); + let can_coerce = self.may_coerce(arg_ty, coerced_ty); + if !can_coerce { + return Compatibility::Incompatible(Some(ty::error::TypeError::Sorts( + ty::error::ExpectedFound::new(coerced_ty, arg_ty), + ))); + } + + // Using probe here, since we don't want this subtyping to affect inference. + let subtyping_error = self.probe(|_| { + self.at(&self.misc(arg_span), self.param_env) + .sup(DefineOpaqueTypes::Yes, formal_input_ty, coerced_ty) + .err() + }); + + // Same as above: if either the coerce type or the checked type is an error type, + // consider them *not* compatible. + let references_error = (coerced_ty, arg_ty).references_error(); + match (references_error, subtyping_error) { + (false, None) => Compatibility::Compatible, + (_, subtyping_error) => Compatibility::Incompatible(subtyping_error), + } + } + + fn remove_idx_is_perfect(&self, idx: usize) -> bool { + let removed_arg_tys = self + .provided_arg_tys + .iter() + .enumerate() + .filter_map(|(j, arg)| if idx == j { None } else { Some(arg) }) + .collect::<IndexVec<ProvidedIdx, _>>(); + std::iter::zip(self.formal_and_expected_inputs.iter(), removed_arg_tys.iter()).all( + |((expected_ty, _), (provided_ty, _))| { + !provided_ty.references_error() && self.may_coerce(*provided_ty, *expected_ty) + }, + ) + } +} + +struct ArgsCtxt<'a, 'b, 'tcx> { + call_ctxt: CallCtxt<'a, 'b, 'tcx>, + call_metadata: CallMetadata, + args_span: Span, +} + +impl<'a, 'b, 'tcx> Deref for ArgsCtxt<'a, 'b, 'tcx> { + type Target = CallCtxt<'a, 'b, 'tcx>; + + fn deref(&self) -> &Self::Target { + &self.call_ctxt + } +} + +impl<'a, 'b, 'tcx> ArgsCtxt<'a, 'b, 'tcx> { + fn new( + arg: &'a FnCtxt<'b, 'tcx>, + compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>, + formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, + provided_args: IndexVec<ProvidedIdx, &'tcx Expr<'tcx>>, + c_variadic: bool, + err_code: ErrCode, + fn_def_id: Option<DefId>, + call_span: Span, + call_expr: &'tcx Expr<'tcx>, + tuple_arguments: TupleArgumentsFlag, + ) -> Self { + let call_ctxt: CallCtxt<'_, '_, '_> = CallCtxt::new( + arg, + compatibility_diagonal, + formal_and_expected_inputs, + provided_args, + c_variadic, + err_code, + fn_def_id, + call_span, + call_expr, + tuple_arguments, + ); + + let call_metadata = call_ctxt.call_metadata(); + let args_span = call_metadata + .error_span + .trim_start(call_metadata.full_call_span) + .unwrap_or(call_metadata.error_span); + + ArgsCtxt { args_span, call_metadata, call_ctxt } + } + + /// Get the argument span in the context of the call span so that + /// suggestions and labels are (more) correct when an arg is a + /// macro invocation. + fn normalize_span(&self, span: Span) -> Span { + let normalized_span = + span.find_ancestor_inside_same_ctxt(self.call_metadata.error_span).unwrap_or(span); + // Sometimes macros mess up the spans, so do not normalize the + // arg span to equal the error span, because that's less useful + // than pointing out the arg expr in the wrong context. + if normalized_span.source_equal(self.call_metadata.error_span) { + span + } else { + normalized_span + } + } + + /// Computes the provided types and spans. + fn provided_arg_tys(&self) -> IndexVec<ProvidedIdx, (Ty<'tcx>, Span)> { + self.call_ctxt + .provided_args + .iter() + .map(|expr| { + let ty = self + .call_ctxt + .fn_ctxt + .typeck_results + .borrow() + .expr_ty_adjusted_opt(*expr) + .unwrap_or_else(|| Ty::new_misc_error(self.call_ctxt.fn_ctxt.tcx)); + ( + self.call_ctxt.fn_ctxt.resolve_vars_if_possible(ty), + self.normalize_span(expr.span), + ) + }) + .collect() + } + + // Obtain another method on `Self` that have similar name. + fn similar_assoc(&self, call_name: Ident) -> Option<(ty::AssocItem, ty::FnSig<'tcx>)> { + if let Some(callee_ty) = self.call_ctxt.callee_ty + && let Ok(Some(assoc)) = self.call_ctxt.fn_ctxt.probe_op( + call_name.span, + MethodCall, + Some(call_name), + None, + IsSuggestion(true), + callee_ty.peel_refs(), + self.call_ctxt.callee_expr.unwrap().hir_id, + TraitsInScope, + |mut ctxt| ctxt.probe_for_similar_candidate(), + ) + && assoc.is_method() + { + let args = + self.call_ctxt.fn_ctxt.infcx.fresh_args_for_item(call_name.span, assoc.def_id); + let fn_sig = self + .call_ctxt + .fn_ctxt + .tcx + .fn_sig(assoc.def_id) + .instantiate(self.call_ctxt.fn_ctxt.tcx, args); + + self.call_ctxt.fn_ctxt.instantiate_binder_with_fresh_vars( + call_name.span, + BoundRegionConversionTime::FnCall, + fn_sig, + ); + } + None + } + + fn call_is_in_macro(&self) -> bool { + self.call_metadata.full_call_span.in_external_macro(self.sess().source_map()) + } +} + +struct CallMetadata { + error_span: Span, + call_ident: Option<Ident>, + full_call_span: Span, + call_name: &'static str, + is_method: bool, +} + +struct CallCtxt<'a, 'b, 'tcx> { + fn_ctxt: &'a FnCtxt<'b, 'tcx>, + compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>, + formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, + provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>, + c_variadic: bool, + err_code: ErrCode, + fn_def_id: Option<DefId>, + call_span: Span, + call_expr: &'tcx hir::Expr<'tcx>, + tuple_arguments: TupleArgumentsFlag, + callee_expr: Option<&'tcx Expr<'tcx>>, + callee_ty: Option<Ty<'tcx>>, +} + +impl<'a, 'b, 'tcx> Deref for CallCtxt<'a, 'b, 'tcx> { + type Target = &'a FnCtxt<'b, 'tcx>; + + fn deref(&self) -> &Self::Target { + &self.fn_ctxt + } +} + +impl<'a, 'b, 'tcx> CallCtxt<'a, 'b, 'tcx> { + fn new( + fn_ctxt: &'a FnCtxt<'b, 'tcx>, + compatibility_diagonal: IndexVec<ProvidedIdx, Compatibility<'tcx>>, + formal_and_expected_inputs: IndexVec<ExpectedIdx, (Ty<'tcx>, Ty<'tcx>)>, + provided_args: IndexVec<ProvidedIdx, &'tcx hir::Expr<'tcx>>, + c_variadic: bool, + err_code: ErrCode, + fn_def_id: Option<DefId>, + call_span: Span, + call_expr: &'tcx hir::Expr<'tcx>, + tuple_arguments: TupleArgumentsFlag, + ) -> CallCtxt<'a, 'b, 'tcx> { + let callee_expr = match &call_expr.peel_blocks().kind { + hir::ExprKind::Call(callee, _) => Some(*callee), + hir::ExprKind::MethodCall(_, receiver, ..) => { + if let Some((DefKind::AssocFn, def_id)) = + fn_ctxt.typeck_results.borrow().type_dependent_def(call_expr.hir_id) + && let Some(assoc) = fn_ctxt.tcx.opt_associated_item(def_id) + && assoc.is_method() + { + Some(*receiver) + } else { + None + } + } + _ => None, + }; + + let callee_ty = callee_expr.and_then(|callee_expr| { + fn_ctxt.typeck_results.borrow().expr_ty_adjusted_opt(callee_expr) + }); + + CallCtxt { + fn_ctxt, + compatibility_diagonal, + formal_and_expected_inputs, + provided_args, + c_variadic, + err_code, + fn_def_id, + call_span, + call_expr, + tuple_arguments, + callee_expr, + callee_ty, + } + } + + fn call_metadata(&self) -> CallMetadata { + match &self.call_expr.kind { + hir::ExprKind::Call( + hir::Expr { hir_id, span, kind: hir::ExprKind::Path(qpath), .. }, + _, + ) => { + if let Res::Def(DefKind::Ctor(of, _), _) = + self.typeck_results.borrow().qpath_res(qpath, *hir_id) + { + let name = match of { + CtorOf::Struct => "struct", + CtorOf::Variant => "enum variant", + }; + CallMetadata { + error_span: self.call_span, + call_ident: None, + full_call_span: *span, + call_name: name, + is_method: false, + } + } else { + CallMetadata { + error_span: self.call_span, + call_ident: None, + full_call_span: *span, + call_name: "function", + is_method: false, + } + } + } + hir::ExprKind::Call(hir::Expr { span, .. }, _) => CallMetadata { + error_span: self.call_span, + call_ident: None, + full_call_span: *span, + call_name: "function", + is_method: false, + }, + hir::ExprKind::MethodCall(path_segment, _, _, span) => { + let ident_span = path_segment.ident.span; + let ident_span = if let Some(args) = path_segment.args { + ident_span.with_hi(args.span_ext.hi()) + } else { + ident_span + }; + CallMetadata { + error_span: *span, + call_ident: Some(path_segment.ident), + full_call_span: ident_span, + call_name: "method", + is_method: true, + } + } + k => span_bug!(self.call_span, "checking argument types on a non-call: `{:?}`", k), + } + } + + fn mk_trace( + &self, + span: Span, + (formal_ty, expected_ty): (Ty<'tcx>, Ty<'tcx>), + provided_ty: Ty<'tcx>, + ) -> TypeTrace<'tcx> { + let mismatched_ty = if expected_ty == provided_ty { + // If expected == provided, then we must have failed to sup + // the formal type. Avoid printing out "expected Ty, found Ty" + // in that case. + formal_ty + } else { + expected_ty + }; + TypeTrace::types(&self.misc(span), mismatched_ty, provided_ty) + } + + fn ty_to_snippet(&self, ty: Ty<'tcx>, expected_idx: ExpectedIdx) -> String { + if ty.is_unit() { + "()".to_string() + } else if ty.is_suggestable(self.tcx, false) { + format!("/* {ty} */") + } else if let Some(fn_def_id) = self.fn_def_id + && self.tcx.def_kind(fn_def_id).is_fn_like() + && let self_implicit = + matches!(self.call_expr.kind, hir::ExprKind::MethodCall(..)) as usize + && let Some(Some(arg)) = + self.tcx.fn_arg_idents(fn_def_id).get(expected_idx.as_usize() + self_implicit) + && arg.name != kw::SelfLower + { + format!("/* {} */", arg.name) + } else { + "/* value */".to_string() + } + } + + fn first_incompatible_error(&self) -> Option<(ProvidedIdx, TypeError<'tcx>)> { + self.compatibility_diagonal.iter_enumerated().find_map(|(i, c)| { + if let Compatibility::Incompatible(Some(terr)) = c { Some((i, *terr)) } else { None } + }) + } +} + +enum SuggestionText { + None, + Provide(bool), + Remove(bool), + Swap, + Reorder, + DidYouMean, +} diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 1998a1884b7..a5c6a7f34ef 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -3021,6 +3021,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { let deref_kind = if checked_ty.is_box() { + // detect Box::new(..) + if let ExprKind::Call(box_new, [_]) = expr.kind + && let ExprKind::Path(qpath) = &box_new.kind + && let Res::Def(DefKind::AssocFn, fn_id) = + self.typeck_results.borrow().qpath_res(qpath, box_new.hir_id) + && let Some(impl_id) = self.tcx.inherent_impl_of_assoc(fn_id) + && self.tcx.type_of(impl_id).skip_binder().is_box() + && self.tcx.item_name(fn_id) == sym::new + { + let l_paren = self.tcx.sess.source_map().next_point(box_new.span); + let r_paren = self.tcx.sess.source_map().end_point(expr.span); + return Some(( + vec![ + (box_new.span.to(l_paren), String::new()), + (r_paren, String::new()), + ], + "consider removing the Box".to_string(), + Applicability::MachineApplicable, + false, + false, + )); + } "unboxing the value" } else if checked_ty.is_ref() { "dereferencing the borrow" diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs index 9a66bd0574c..4a252719694 100644 --- a/compiler/rustc_infer/src/traits/engine.rs +++ b/compiler/rustc_infer/src/traits/engine.rs @@ -72,12 +72,27 @@ pub trait TraitEngine<'tcx, E: 'tcx>: 'tcx { self.register_predicate_obligation(infcx, obligation); } } - + /// Go over the list of pending obligations and try to evaluate them. + /// + /// For each result: + /// Ok: remove the obligation from the list + /// Ambiguous: leave the obligation in the list to be evaluated later + /// Err: remove the obligation from the list and return an error + /// + /// Returns a list of errors from obligations that evaluated to Err. #[must_use] fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E>; fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E>; + /// Evaluate all pending obligations, return error if they can't be evaluated. + /// + /// For each result: + /// Ok: remove the obligation from the list + /// Ambiguous: remove the obligation from the list and return an error + /// Err: remove the obligation from the list and return an error + /// + /// Returns a list of errors from obligations that evaluated to Ambiguous or Err. #[must_use] fn select_all_or_error(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<E> { let errors = self.select_where_possible(infcx); diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 22d89d24612..edbbfba4f34 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -843,6 +843,10 @@ trait UnusedDelimLint { && !snip.ends_with(' ') { " " + } else if let Ok(snip) = sm.span_to_prev_source(value_span) + && snip.ends_with(|c: char| c.is_alphanumeric()) + { + " " } else { "" }; @@ -852,6 +856,10 @@ trait UnusedDelimLint { && !snip.starts_with(' ') { " " + } else if let Ok(snip) = sm.span_to_prev_source(value_span) + && snip.starts_with(|c: char| c.is_alphanumeric()) + { + " " } else { "" }; diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 9d21d0d22e3..2cfda7a5fb4 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -16,7 +16,6 @@ const OPTIONAL_COMPONENTS: &[&str] = &[ "mips", "powerpc", "systemz", - "jsbackend", "webassembly", "msp430", "sparc", diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 3bb1533c2fe..ab5d5c03e81 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -79,122 +79,6 @@ extern "C" void LLVMRustTimeTraceProfilerFinish(const char *FileName) { timeTraceProfilerCleanup(); } -#ifdef LLVM_COMPONENT_X86 -#define SUBTARGET_X86 SUBTARGET(X86) -#else -#define SUBTARGET_X86 -#endif - -#ifdef LLVM_COMPONENT_ARM -#define SUBTARGET_ARM SUBTARGET(ARM) -#else -#define SUBTARGET_ARM -#endif - -#ifdef LLVM_COMPONENT_AARCH64 -#define SUBTARGET_AARCH64 SUBTARGET(AArch64) -#else -#define SUBTARGET_AARCH64 -#endif - -#ifdef LLVM_COMPONENT_AVR -#define SUBTARGET_AVR SUBTARGET(AVR) -#else -#define SUBTARGET_AVR -#endif - -#ifdef LLVM_COMPONENT_M68k -#define SUBTARGET_M68K SUBTARGET(M68k) -#else -#define SUBTARGET_M68K -#endif - -#ifdef LLVM_COMPONENT_CSKY -#define SUBTARGET_CSKY SUBTARGET(CSKY) -#else -#define SUBTARGET_CSKY -#endif - -#ifdef LLVM_COMPONENT_MIPS -#define SUBTARGET_MIPS SUBTARGET(Mips) -#else -#define SUBTARGET_MIPS -#endif - -#ifdef LLVM_COMPONENT_POWERPC -#define SUBTARGET_PPC SUBTARGET(PPC) -#else -#define SUBTARGET_PPC -#endif - -#ifdef LLVM_COMPONENT_SYSTEMZ -#define SUBTARGET_SYSTEMZ SUBTARGET(SystemZ) -#else -#define SUBTARGET_SYSTEMZ -#endif - -#ifdef LLVM_COMPONENT_MSP430 -#define SUBTARGET_MSP430 SUBTARGET(MSP430) -#else -#define SUBTARGET_MSP430 -#endif - -#ifdef LLVM_COMPONENT_RISCV -#define SUBTARGET_RISCV SUBTARGET(RISCV) -#else -#define SUBTARGET_RISCV -#endif - -#ifdef LLVM_COMPONENT_SPARC -#define SUBTARGET_SPARC SUBTARGET(Sparc) -#else -#define SUBTARGET_SPARC -#endif - -#ifdef LLVM_COMPONENT_XTENSA -#define SUBTARGET_XTENSA SUBTARGET(XTENSA) -#else -#define SUBTARGET_XTENSA -#endif - -#ifdef LLVM_COMPONENT_HEXAGON -#define SUBTARGET_HEXAGON SUBTARGET(Hexagon) -#else -#define SUBTARGET_HEXAGON -#endif - -#ifdef LLVM_COMPONENT_LOONGARCH -#define SUBTARGET_LOONGARCH SUBTARGET(LoongArch) -#else -#define SUBTARGET_LOONGARCH -#endif - -#define GEN_SUBTARGETS \ - SUBTARGET_X86 \ - SUBTARGET_ARM \ - SUBTARGET_AARCH64 \ - SUBTARGET_AVR \ - SUBTARGET_M68K \ - SUBTARGET_CSKY \ - SUBTARGET_MIPS \ - SUBTARGET_PPC \ - SUBTARGET_SYSTEMZ \ - SUBTARGET_MSP430 \ - SUBTARGET_SPARC \ - SUBTARGET_HEXAGON \ - SUBTARGET_XTENSA \ - SUBTARGET_RISCV \ - SUBTARGET_LOONGARCH - -#define SUBTARGET(x) \ - namespace llvm { \ - extern const SubtargetFeatureKV x##FeatureKV[]; \ - extern const SubtargetFeatureKV x##SubTypeKV[]; \ - } - -GEN_SUBTARGETS -#undef SUBTARGET - // This struct and various functions are sort of a hack right now, but the // problem is that we've got in-memory LLVM modules after we generate and // optimize all codegen-units for one compilation in rustc. To be compatible @@ -340,14 +224,6 @@ static FloatABI::ABIType fromRust(LLVMRustFloatABI RustFloatAbi) { report_fatal_error("Bad FloatABI."); } -/// getLongestEntryLength - Return the length of the longest entry in the table. -template <typename KV> static size_t getLongestEntryLength(ArrayRef<KV> Table) { - size_t MaxLen = 0; - for (auto &I : Table) - MaxLen = std::max(MaxLen, std::strlen(I.Key)); - return MaxLen; -} - extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, RustStringRef OutStr) { ArrayRef<SubtargetSubTypeKV> CPUTable = @@ -468,7 +344,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( Options.EmitStackSizeSection = EmitStackSizeSection; if (ArgsCstrBuff != nullptr) { -#if LLVM_VERSION_GE(20, 0) size_t buffer_offset = 0; assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0'); auto Arg0 = std::string(ArgsCstrBuff); @@ -486,33 +361,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( OS.flush(); Options.MCOptions.Argv0 = Arg0; Options.MCOptions.CommandlineArgs = CommandlineArgs; -#else - size_t buffer_offset = 0; - assert(ArgsCstrBuff[ArgsCstrBuffLen - 1] == '\0'); - - const size_t arg0_len = std::strlen(ArgsCstrBuff); - char *arg0 = new char[arg0_len + 1]; - memcpy(arg0, ArgsCstrBuff, arg0_len); - arg0[arg0_len] = '\0'; - buffer_offset += arg0_len + 1; - - const size_t num_cmd_arg_strings = std::count( - &ArgsCstrBuff[buffer_offset], &ArgsCstrBuff[ArgsCstrBuffLen], '\0'); - - std::string *cmd_arg_strings = new std::string[num_cmd_arg_strings]; - for (size_t i = 0; i < num_cmd_arg_strings; ++i) { - assert(buffer_offset < ArgsCstrBuffLen); - const size_t len = std::strlen(ArgsCstrBuff + buffer_offset); - cmd_arg_strings[i] = std::string(&ArgsCstrBuff[buffer_offset], len); - buffer_offset += len + 1; - } - - assert(buffer_offset == ArgsCstrBuffLen); - - Options.MCOptions.Argv0 = arg0; - Options.MCOptions.CommandLineArgs = - llvm::ArrayRef<std::string>(cmd_arg_strings, num_cmd_arg_strings); -#endif } #if LLVM_VERSION_GE(21, 0) @@ -526,12 +374,6 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine( } extern "C" void LLVMRustDisposeTargetMachine(LLVMTargetMachineRef TM) { -#if LLVM_VERSION_LT(20, 0) - MCTargetOptions &MCOptions = unwrap(TM)->Options.MCOptions; - delete[] MCOptions.Argv0; - delete[] MCOptions.CommandLineArgs.data(); -#endif - delete unwrap(TM); } @@ -812,14 +654,9 @@ extern "C" LLVMRustResult LLVMRustOptimize( // the PassBuilder does not create a pipeline. std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>> PipelineStartEPCallbacks; -#if LLVM_VERSION_GE(20, 0) std::vector<std::function<void(ModulePassManager &, OptimizationLevel, ThinOrFullLTOPhase)>> OptimizerLastEPCallbacks; -#else - std::vector<std::function<void(ModulePassManager &, OptimizationLevel)>> - OptimizerLastEPCallbacks; -#endif if (!IsLinkerPluginLTO && SanitizerOptions && SanitizerOptions->SanitizeCFI && !NoPrepopulatePasses) { @@ -871,12 +708,8 @@ extern "C" LLVMRustResult LLVMRustOptimize( SanitizerOptions->SanitizeDataFlowABIList + SanitizerOptions->SanitizeDataFlowABIListLen); OptimizerLastEPCallbacks.push_back( -#if LLVM_VERSION_GE(20, 0) [ABIListFiles](ModulePassManager &MPM, OptimizationLevel Level, ThinOrFullLTOPhase phase) { -#else - [ABIListFiles](ModulePassManager &MPM, OptimizationLevel Level) { -#endif MPM.addPass(DataFlowSanitizerPass(ABIListFiles)); }); } @@ -887,66 +720,48 @@ extern "C" LLVMRustResult LLVMRustOptimize( SanitizerOptions->SanitizeMemoryRecover, /*CompileKernel=*/false, /*EagerChecks=*/true); - OptimizerLastEPCallbacks.push_back( -#if LLVM_VERSION_GE(20, 0) - [Options](ModulePassManager &MPM, OptimizationLevel Level, - ThinOrFullLTOPhase phase) { -#else - [Options](ModulePassManager &MPM, OptimizationLevel Level) { -#endif - MPM.addPass(MemorySanitizerPass(Options)); - }); + OptimizerLastEPCallbacks.push_back([Options](ModulePassManager &MPM, + OptimizationLevel Level, + ThinOrFullLTOPhase phase) { + MPM.addPass(MemorySanitizerPass(Options)); + }); } if (SanitizerOptions->SanitizeThread) { - OptimizerLastEPCallbacks.push_back( -#if LLVM_VERSION_GE(20, 0) - [](ModulePassManager &MPM, OptimizationLevel Level, - ThinOrFullLTOPhase phase) { -#else - [](ModulePassManager &MPM, OptimizationLevel Level) { -#endif - MPM.addPass(ModuleThreadSanitizerPass()); - MPM.addPass( - createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); - }); + OptimizerLastEPCallbacks.push_back([](ModulePassManager &MPM, + OptimizationLevel Level, + ThinOrFullLTOPhase phase) { + MPM.addPass(ModuleThreadSanitizerPass()); + MPM.addPass(createModuleToFunctionPassAdaptor(ThreadSanitizerPass())); + }); } if (SanitizerOptions->SanitizeAddress || SanitizerOptions->SanitizeKernelAddress) { - OptimizerLastEPCallbacks.push_back( -#if LLVM_VERSION_GE(20, 0) - [SanitizerOptions, TM](ModulePassManager &MPM, - OptimizationLevel Level, - ThinOrFullLTOPhase phase) { -#else - [SanitizerOptions, TM](ModulePassManager &MPM, - OptimizationLevel Level) { -#endif - auto CompileKernel = SanitizerOptions->SanitizeKernelAddress; - AddressSanitizerOptions opts = AddressSanitizerOptions{ - CompileKernel, - SanitizerOptions->SanitizeAddressRecover || - SanitizerOptions->SanitizeKernelAddressRecover, - /*UseAfterScope=*/true, - AsanDetectStackUseAfterReturnMode::Runtime, - }; - MPM.addPass(AddressSanitizerPass( - opts, - /*UseGlobalGC*/ true, - // UseOdrIndicator should be false on windows machines - // https://reviews.llvm.org/D137227 - !TM->getTargetTriple().isOSWindows())); - }); + OptimizerLastEPCallbacks.push_back([SanitizerOptions, + TM](ModulePassManager &MPM, + OptimizationLevel Level, + ThinOrFullLTOPhase phase) { + auto CompileKernel = SanitizerOptions->SanitizeKernelAddress; + AddressSanitizerOptions opts = AddressSanitizerOptions{ + CompileKernel, + SanitizerOptions->SanitizeAddressRecover || + SanitizerOptions->SanitizeKernelAddressRecover, + /*UseAfterScope=*/true, + AsanDetectStackUseAfterReturnMode::Runtime, + }; + MPM.addPass( + AddressSanitizerPass(opts, + /*UseGlobalGC*/ true, + // UseOdrIndicator should be false on windows + // machines https://reviews.llvm.org/D137227 + !TM->getTargetTriple().isOSWindows())); + }); } if (SanitizerOptions->SanitizeHWAddress) { OptimizerLastEPCallbacks.push_back( -#if LLVM_VERSION_GE(20, 0) [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level, ThinOrFullLTOPhase phase) { -#else - [SanitizerOptions](ModulePassManager &MPM, OptimizationLevel Level) { -#endif HWAddressSanitizerOptions opts( /*CompileKernel=*/false, SanitizerOptions->SanitizeHWAddressRecover, @@ -1028,11 +843,7 @@ extern "C" LLVMRustResult LLVMRustOptimize( for (const auto &C : PipelineStartEPCallbacks) C(MPM, OptLevel); for (const auto &C : OptimizerLastEPCallbacks) -#if LLVM_VERSION_GE(20, 0) C(MPM, OptLevel, ThinOrFullLTOPhase::None); -#else - C(MPM, OptLevel); -#endif } if (ExtraPassesLen) { @@ -1309,11 +1120,7 @@ struct LLVMRustThinLTOData { // Not 100% sure what these are, but they impact what's internalized and // what's inlined across modules, I believe. -#if LLVM_VERSION_GE(20, 0) FunctionImporter::ImportListsTy ImportLists; -#else - DenseMap<StringRef, FunctionImporter::ImportMapTy> ImportLists; -#endif DenseMap<StringRef, FunctionImporter::ExportSetTy> ExportLists; DenseMap<StringRef, GVSummaryMapTy> ModuleToDefinedGVSummaries; StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; @@ -1655,13 +1462,8 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, const auto &ExportList = Data->ExportLists.lookup(ModId); const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId); const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId); -#if LLVM_VERSION_GE(20, 0) DenseSet<GlobalValue::GUID> CfiFunctionDefs; DenseSet<GlobalValue::GUID> CfiFunctionDecls; -#else - std::set<GlobalValue::GUID> CfiFunctionDefs; - std::set<GlobalValue::GUID> CfiFunctionDecls; -#endif // Based on the 'InProcessThinBackend' constructor in LLVM #if LLVM_VERSION_GE(21, 0) @@ -1680,15 +1482,9 @@ extern "C" void LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); #endif -#if LLVM_VERSION_GE(20, 0) Key = llvm::computeLTOCacheKey(conf, Data->Index, ModId, ImportList, ExportList, ResolvedODR, DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls); -#else - llvm::computeLTOCacheKey(Key, conf, Data->Index, ModId, ImportList, - ExportList, ResolvedODR, DefinedGlobals, - CfiFunctionDefs, CfiFunctionDecls); -#endif auto OS = RawRustStringOstream(KeyOut); OS << Key.str(); diff --git a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 361a5f76551..b4ca641674f 100644 --- a/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1026,13 +1026,6 @@ LLVMRustDIBuilderCreateFile(LLVMDIBuilderRef Builder, const char *Filename, CSInfo, oSource)); } -extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateSubroutineType(LLVMDIBuilderRef Builder, - LLVMMetadataRef ParameterTypes) { - return wrap(unwrap(Builder)->createSubroutineType( - DITypeRefArray(unwrap<MDTuple>(ParameterTypes)))); -} - extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateFunction( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, const char *LinkageName, size_t LinkageNameLen, @@ -1072,14 +1065,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateMethod( } extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateBasicType(LLVMDIBuilderRef Builder, const char *Name, - size_t NameLen, uint64_t SizeInBits, - unsigned Encoding) { - return wrap(unwrap(Builder)->createBasicType(StringRef(Name, NameLen), - SizeInBits, Encoding)); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTypedef(LLVMDIBuilderRef Builder, LLVMMetadataRef Type, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNo, @@ -1089,29 +1074,6 @@ LLVMRustDIBuilderCreateTypedef(LLVMDIBuilderRef Builder, LLVMMetadataRef Type, LineNo, unwrapDIPtr<DIScope>(Scope))); } -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreatePointerType( - LLVMDIBuilderRef Builder, LLVMMetadataRef PointeeTy, uint64_t SizeInBits, - uint32_t AlignInBits, unsigned AddressSpace, const char *Name, - size_t NameLen) { - return wrap(unwrap(Builder)->createPointerType( - unwrapDI<DIType>(PointeeTy), SizeInBits, AlignInBits, AddressSpace, - StringRef(Name, NameLen))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateStructType( - LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, - size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, - uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags, - LLVMMetadataRef DerivedFrom, LLVMMetadataRef Elements, unsigned RunTimeLang, - LLVMMetadataRef VTableHolder, const char *UniqueId, size_t UniqueIdLen) { - return wrap(unwrap(Builder)->createStructType( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits, - fromRust(Flags), unwrapDI<DIType>(DerivedFrom), - DINodeArray(unwrapDI<MDTuple>(Elements)), RunTimeLang, - unwrapDI<DIType>(VTableHolder), StringRef(UniqueId, UniqueIdLen))); -} - extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariantPart( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, @@ -1219,15 +1181,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateVariable( } extern "C" LLVMMetadataRef -LLVMRustDIBuilderCreateArrayType(LLVMDIBuilderRef Builder, uint64_t Size, - uint32_t AlignInBits, LLVMMetadataRef Ty, - LLVMMetadataRef Subscripts) { - return wrap(unwrap(Builder)->createArrayType( - Size, AlignInBits, unwrapDI<DIType>(Ty), - DINodeArray(unwrapDI<MDTuple>(Subscripts)))); -} - -extern "C" LLVMMetadataRef LLVMRustDIBuilderGetOrCreateSubrange(LLVMDIBuilderRef Builder, int64_t Lo, int64_t Count) { return wrap(unwrap(Builder)->getOrCreateSubrange(Lo, Count)); @@ -1275,19 +1228,6 @@ extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateEnumerationType( /* RunTimeLang */ 0, "", IsScoped)); } -extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateUnionType( - LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, - size_t NameLen, LLVMMetadataRef File, unsigned LineNumber, - uint64_t SizeInBits, uint32_t AlignInBits, LLVMDIFlags Flags, - LLVMMetadataRef Elements, unsigned RunTimeLang, const char *UniqueId, - size_t UniqueIdLen) { - return wrap(unwrap(Builder)->createUnionType( - unwrapDI<DIDescriptor>(Scope), StringRef(Name, NameLen), - unwrapDI<DIFile>(File), LineNumber, SizeInBits, AlignInBits, - fromRust(Flags), DINodeArray(unwrapDI<MDTuple>(Elements)), RunTimeLang, - StringRef(UniqueId, UniqueIdLen))); -} - extern "C" LLVMMetadataRef LLVMRustDIBuilderCreateTemplateTypeParameter( LLVMDIBuilderRef Builder, LLVMMetadataRef Scope, const char *Name, size_t NameLen, LLVMMetadataRef Ty) { diff --git a/compiler/rustc_llvm/src/lib.rs b/compiler/rustc_llvm/src/lib.rs index ed5edeef161..14e94121d1c 100644 --- a/compiler/rustc_llvm/src/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -180,12 +180,6 @@ pub fn initialize_available_targets() { LLVMInitializeSystemZAsmParser ); init_target!( - llvm_component = "jsbackend", - LLVMInitializeJSBackendTargetInfo, - LLVMInitializeJSBackendTarget, - LLVMInitializeJSBackendTargetMC - ); - init_target!( llvm_component = "msp430", LLVMInitializeMSP430TargetInfo, LLVMInitializeMSP430Target, diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl index 69adb2fe391..279ab9a9d8f 100644 --- a/compiler/rustc_middle/messages.ftl +++ b/compiler/rustc_middle/messages.ftl @@ -84,7 +84,7 @@ middle_failed_writing_file = # Note: We only mention patterns here since the error can only occur with references, and those # are forbidden in const generics. middle_invalid_const_in_valtree = constant {$global_const_id} cannot be used as pattern - .note = constants that reference mutable or external memory cannot be used as pattern + .note = constants that reference mutable or external memory cannot be used as patterns middle_layout_cycle = a cycle occurred during layout computation diff --git a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 8b4503073b0..f0d96c6ac89 100644 --- a/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -69,6 +69,10 @@ pub struct CodegenFnAttrs { /// The `#[patchable_function_entry(...)]` attribute. Indicates how many nops should be around /// the function entry. pub patchable_function_entry: Option<PatchableFunctionEntry>, + /// The `#[rustc_objc_class = "..."]` attribute. + pub objc_class: Option<Symbol>, + /// The `#[rustc_objc_selector = "..."]` attribute. + pub objc_selector: Option<Symbol>, } #[derive(Copy, Clone, Debug, TyEncodable, TyDecodable, HashStable, PartialEq, Eq)] @@ -185,6 +189,8 @@ impl CodegenFnAttrs { instruction_set: None, alignment: None, patchable_function_entry: None, + objc_class: None, + objc_selector: None, } } diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs index 67962813ae4..8e603ce1b91 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -849,8 +849,13 @@ impl<Prov: Provenance, Extra, Bytes: AllocBytes> Allocation<Prov, Extra, Bytes> /// /// This is dangerous to use as it can violate internal `Allocation` invariants! /// It only exists to support an efficient implementation of `mem_copy_repeatedly`. - pub fn provenance_apply_copy(&mut self, copy: ProvenanceCopy<Prov>) { - self.provenance.apply_copy(copy) + pub fn provenance_apply_copy( + &mut self, + copy: ProvenanceCopy<Prov>, + range: AllocRange, + repeat: u64, + ) { + self.provenance.apply_copy(copy, range, repeat) } /// Applies a previously prepared copy of the init mask. diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs index 720e58d7aa0..67baf63bbfa 100644 --- a/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation/provenance_map.rs @@ -278,90 +278,78 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { /// A partial, owned list of provenance to transfer into another allocation. /// -/// Offsets are already adjusted to the destination allocation. +/// Offsets are relative to the beginning of the copied range. pub struct ProvenanceCopy<Prov> { - dest_ptrs: Option<Box<[(Size, Prov)]>>, - dest_bytes: Option<Box<[(Size, (Prov, u8))]>>, + ptrs: Box<[(Size, Prov)]>, + bytes: Box<[(Size, (Prov, u8))]>, } impl<Prov: Provenance> ProvenanceMap<Prov> { pub fn prepare_copy( &self, - src: AllocRange, - dest: Size, - count: u64, + range: AllocRange, cx: &impl HasDataLayout, ) -> AllocResult<ProvenanceCopy<Prov>> { - let shift_offset = move |idx, offset| { - // compute offset for current repetition - let dest_offset = dest + src.size * idx; // `Size` operations - // shift offsets from source allocation to destination allocation - (offset - src.start) + dest_offset // `Size` operations - }; + let shift_offset = move |offset| offset - range.start; let ptr_size = cx.data_layout().pointer_size(); // # Pointer-sized provenances // Get the provenances that are entirely within this range. // (Different from `range_get_ptrs` which asks if they overlap the range.) // Only makes sense if we are copying at least one pointer worth of bytes. - let mut dest_ptrs_box = None; - if src.size >= ptr_size { - let adjusted_end = Size::from_bytes(src.end().bytes() - (ptr_size.bytes() - 1)); - let ptrs = self.ptrs.range(src.start..adjusted_end); - // If `count` is large, this is rather wasteful -- we are allocating a big array here, which - // is mostly filled with redundant information since it's just N copies of the same `Prov`s - // at slightly adjusted offsets. The reason we do this is so that in `mark_provenance_range` - // we can use `insert_presorted`. That wouldn't work with an `Iterator` that just produces - // the right sequence of provenance for all N copies. - // Basically, this large array would have to be created anyway in the target allocation. - let mut dest_ptrs = Vec::with_capacity(ptrs.len() * (count as usize)); - for i in 0..count { - dest_ptrs - .extend(ptrs.iter().map(|&(offset, reloc)| (shift_offset(i, offset), reloc))); - } - debug_assert_eq!(dest_ptrs.len(), dest_ptrs.capacity()); - dest_ptrs_box = Some(dest_ptrs.into_boxed_slice()); + let mut ptrs_box: Box<[_]> = Box::new([]); + if range.size >= ptr_size { + let adjusted_end = Size::from_bytes(range.end().bytes() - (ptr_size.bytes() - 1)); + let ptrs = self.ptrs.range(range.start..adjusted_end); + ptrs_box = ptrs.iter().map(|&(offset, reloc)| (shift_offset(offset), reloc)).collect(); }; // # Byte-sized provenances // This includes the existing bytewise provenance in the range, and ptr provenance // that overlaps with the begin/end of the range. - let mut dest_bytes_box = None; - let begin_overlap = self.range_ptrs_get(alloc_range(src.start, Size::ZERO), cx).first(); - let end_overlap = self.range_ptrs_get(alloc_range(src.end(), Size::ZERO), cx).first(); + let mut bytes_box: Box<[_]> = Box::new([]); + let begin_overlap = self.range_ptrs_get(alloc_range(range.start, Size::ZERO), cx).first(); + let end_overlap = self.range_ptrs_get(alloc_range(range.end(), Size::ZERO), cx).first(); // We only need to go here if there is some overlap or some bytewise provenance. if begin_overlap.is_some() || end_overlap.is_some() || self.bytes.is_some() { let mut bytes: Vec<(Size, (Prov, u8))> = Vec::new(); // First, if there is a part of a pointer at the start, add that. if let Some(entry) = begin_overlap { trace!("start overlapping entry: {entry:?}"); - // For really small copies, make sure we don't run off the end of the `src` range. - let entry_end = cmp::min(entry.0 + ptr_size, src.end()); - for offset in src.start..entry_end { - bytes.push((offset, (entry.1, (offset - entry.0).bytes() as u8))); + // For really small copies, make sure we don't run off the end of the range. + let entry_end = cmp::min(entry.0 + ptr_size, range.end()); + for offset in range.start..entry_end { + bytes.push((shift_offset(offset), (entry.1, (offset - entry.0).bytes() as u8))); } } else { trace!("no start overlapping entry"); } // Then the main part, bytewise provenance from `self.bytes`. - bytes.extend(self.range_bytes_get(src)); + bytes.extend( + self.range_bytes_get(range) + .iter() + .map(|&(offset, reloc)| (shift_offset(offset), reloc)), + ); // And finally possibly parts of a pointer at the end. if let Some(entry) = end_overlap { trace!("end overlapping entry: {entry:?}"); - // For really small copies, make sure we don't start before `src` does. - let entry_start = cmp::max(entry.0, src.start); - for offset in entry_start..src.end() { + // For really small copies, make sure we don't start before `range` does. + let entry_start = cmp::max(entry.0, range.start); + for offset in entry_start..range.end() { if bytes.last().is_none_or(|bytes_entry| bytes_entry.0 < offset) { // The last entry, if it exists, has a lower offset than us, so we // can add it at the end and remain sorted. - bytes.push((offset, (entry.1, (offset - entry.0).bytes() as u8))); + bytes.push(( + shift_offset(offset), + (entry.1, (offset - entry.0).bytes() as u8), + )); } else { // There already is an entry for this offset in there! This can happen when the // start and end range checks actually end up hitting the same pointer, so we // already added this in the "pointer at the start" part above. - assert!(entry.0 <= src.start); + assert!(entry.0 <= range.start); } } } else { @@ -372,33 +360,40 @@ impl<Prov: Provenance> ProvenanceMap<Prov> { if !bytes.is_empty() && !Prov::OFFSET_IS_ADDR { // FIXME(#146291): We need to ensure that we don't mix different pointers with // the same provenance. - return Err(AllocError::ReadPartialPointer(src.start)); + return Err(AllocError::ReadPartialPointer(range.start)); } // And again a buffer for the new list on the target side. - let mut dest_bytes = Vec::with_capacity(bytes.len() * (count as usize)); - for i in 0..count { - dest_bytes - .extend(bytes.iter().map(|&(offset, reloc)| (shift_offset(i, offset), reloc))); - } - debug_assert_eq!(dest_bytes.len(), dest_bytes.capacity()); - dest_bytes_box = Some(dest_bytes.into_boxed_slice()); + bytes_box = bytes.into_boxed_slice(); } - Ok(ProvenanceCopy { dest_ptrs: dest_ptrs_box, dest_bytes: dest_bytes_box }) + Ok(ProvenanceCopy { ptrs: ptrs_box, bytes: bytes_box }) } /// Applies a provenance copy. /// The affected range, as defined in the parameters to `prepare_copy` is expected /// to be clear of provenance. - pub fn apply_copy(&mut self, copy: ProvenanceCopy<Prov>) { - if let Some(dest_ptrs) = copy.dest_ptrs { - self.ptrs.insert_presorted(dest_ptrs.into()); + pub fn apply_copy(&mut self, copy: ProvenanceCopy<Prov>, range: AllocRange, repeat: u64) { + let shift_offset = |idx: u64, offset: Size| offset + range.start + idx * range.size; + if !copy.ptrs.is_empty() { + // We want to call `insert_presorted` only once so that, if possible, the entries + // after the range we insert are moved back only once. + let chunk_len = copy.ptrs.len() as u64; + self.ptrs.insert_presorted((0..chunk_len * repeat).map(|i| { + let chunk = i / chunk_len; + let (offset, reloc) = copy.ptrs[(i % chunk_len) as usize]; + (shift_offset(chunk, offset), reloc) + })); } - if let Some(dest_bytes) = copy.dest_bytes - && !dest_bytes.is_empty() - { - self.bytes.get_or_insert_with(Box::default).insert_presorted(dest_bytes.into()); + if !copy.bytes.is_empty() { + let chunk_len = copy.bytes.len() as u64; + self.bytes.get_or_insert_with(Box::default).insert_presorted( + (0..chunk_len * repeat).map(|i| { + let chunk = i / chunk_len; + let (offset, reloc) = copy.bytes[(i % chunk_len) as usize]; + (shift_offset(chunk, offset), reloc) + }), + ); } } } diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index da2245b12d2..28142382b13 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -471,7 +471,7 @@ impl<'tcx> Body<'tcx> { /// Returns an iterator over all function arguments. #[inline] - pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator { + pub fn args_iter(&self) -> impl Iterator<Item = Local> + ExactSizeIterator + use<> { (1..self.arg_count + 1).map(Local::new) } diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index f9d0a5f0a3b..96148fd5b92 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -1062,7 +1062,6 @@ impl<'tcx> Debug for Rvalue<'tcx> { pretty_print_const(b, fmt, false)?; write!(fmt, "]") } - Len(ref a) => write!(fmt, "Len({a:?})"), Cast(ref kind, ref place, ref ty) => { with_no_trimmed_paths!(write!(fmt, "{place:?} as {ty} ({kind:?})")) } diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 466b9c7a3c2..a509c40c89c 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -17,7 +17,7 @@ use crate::ty::{self, CoroutineArgsExt, OpaqueHiddenType, Ty}; rustc_index::newtype_index! { #[derive(HashStable)] #[encodable] - #[debug_format = "_{}"] + #[debug_format = "_s{}"] pub struct CoroutineSavedLocal {} } diff --git a/compiler/rustc_middle/src/mir/statement.rs b/compiler/rustc_middle/src/mir/statement.rs index ec2a8e86077..28294b47e90 100644 --- a/compiler/rustc_middle/src/mir/statement.rs +++ b/compiler/rustc_middle/src/mir/statement.rs @@ -697,7 +697,6 @@ impl<'tcx> Rvalue<'tcx> { | Rvalue::Ref(_, _, _) | Rvalue::ThreadLocalRef(_) | Rvalue::RawPtr(_, _) - | Rvalue::Len(_) | Rvalue::Cast( CastKind::IntToInt | CastKind::FloatToInt @@ -739,7 +738,6 @@ impl<'tcx> Rvalue<'tcx> { let place_ty = place.ty(local_decls, tcx).ty; Ty::new_ptr(tcx, place_ty, kind.to_mutbl_lossy()) } - Rvalue::Len(..) => tcx.types.usize, Rvalue::Cast(.., ty) => ty, Rvalue::BinaryOp(op, box (ref lhs, ref rhs)) => { let lhs_ty = lhs.ty(local_decls, tcx); diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 3b8def67f92..e6c8512564e 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -327,9 +327,11 @@ pub enum StatementKind<'tcx> { /// interesting for optimizations? Do we want to allow such optimizations? /// /// **Needs clarification**: We currently require that the LHS place not overlap with any place - /// read as part of computation of the RHS for some rvalues (generally those not producing - /// primitives). This requirement is under discussion in [#68364]. As a part of this discussion, - /// it is also unclear in what order the components are evaluated. + /// read as part of computation of the RHS for some rvalues. This requirement is under + /// discussion in [#68364]. Specifically, overlap is permitted only for assignments of a type + /// with `BackendRepr::Scalar | BackendRepr::ScalarPair` where all the scalar fields are + /// [`Scalar::Initialized`][rustc_abi::Scalar::Initialized]. As a part of this discussion, it is + /// also unclear in what order the components are evaluated. /// /// [#68364]: https://github.com/rust-lang/rust/issues/68364 /// @@ -1405,16 +1407,6 @@ pub enum Rvalue<'tcx> { /// model. RawPtr(RawPtrKind, Place<'tcx>), - /// Yields the length of the place, as a `usize`. - /// - /// If the type of the place is an array, this is the array length. For slices (`[T]`, not - /// `&[T]`) this accesses the place's metadata to determine the length. This rvalue is - /// ill-formed for places of other types. - /// - /// This cannot be a `UnOp(PtrMetadata, _)` because that expects a value, and we only - /// have a place, and `UnOp(PtrMetadata, RawPtr(place))` is not a thing. - Len(Place<'tcx>), - /// Performs essentially all of the casts that can be performed via `as`. /// /// This allows for casts from/to a variety of types. diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs index b498b7b8912..07a15b3cd18 100644 --- a/compiler/rustc_middle/src/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -717,14 +717,6 @@ macro_rules! make_mir_visitor { self.visit_place(path, ctx, location); } - Rvalue::Len(path) => { - self.visit_place( - path, - PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect), - location - ); - } - Rvalue::Cast(_cast_kind, operand, ty) => { self.visit_operand(operand, location); self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)); diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 029586a9c55..b79b67c5927 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -1359,6 +1359,7 @@ impl<'tcx> Ty<'tcx> { /// 2229 drop reorder migration analysis. #[inline] pub fn has_significant_drop(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool { + assert!(!self.has_non_region_infer()); // Avoid querying in simple cases. match needs_drop_components(tcx, self) { Err(AlwaysRequiresDrop) => true, @@ -1371,14 +1372,6 @@ impl<'tcx> Ty<'tcx> { _ => self, }; - // FIXME(#86868): We should be canonicalizing, or else moving this to a method of inference - // context, or *something* like that, but for now just avoid passing inference - // variables to queries that can't cope with them. Instead, conservatively - // return "true" (may change drop order). - if query_ty.has_infer() { - return true; - } - // This doesn't depend on regions, so try to minimize distinct // query keys used. let erased = tcx.normalize_erasing_regions(typing_env, query_ty); diff --git a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs index 41d3aefcbe6..54490e00509 100644 --- a/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs +++ b/compiler/rustc_mir_build/src/builder/custom/parse/instruction.rs @@ -229,6 +229,11 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let source = self.parse_operand(args[0])?; Ok(Rvalue::Cast(CastKind::PtrToPtr, source, expr.ty)) }, + @call(mir_cast_unsize, args) => { + let source = self.parse_operand(args[0])?; + let kind = CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, CoercionSource::AsCast); + Ok(Rvalue::Cast(kind, source, expr.ty)) + }, @call(mir_checked, args) => { parse_by_kind!(self, args[0], _, "binary op", ExprKind::Binary { op, lhs, rhs } => { @@ -247,7 +252,6 @@ impl<'a, 'tcx> ParseCtxt<'a, 'tcx> { let offset = self.parse_operand(args[1])?; Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset)))) }, - @call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)), @call(mir_ptr_metadata, args) => Ok(Rvalue::UnaryOp(UnOp::PtrMetadata, self.parse_operand(args[0])?)), @call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)), ExprKind::Borrow { borrow_kind, arg } => Ok( diff --git a/compiler/rustc_mir_build/src/builder/expr/as_place.rs b/compiler/rustc_mir_build/src/builder/expr/as_place.rs index 7c851ec465b..5a6bd2f413c 100644 --- a/compiler/rustc_mir_build/src/builder/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/builder/expr/as_place.rs @@ -663,7 +663,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { /// /// For arrays it'll be `Operand::Constant` with the actual length; /// For slices it'll be `Operand::Move` of a local using `PtrMetadata`. - fn len_of_slice_or_array( + pub(in crate::builder) fn len_of_slice_or_array( &mut self, block: BasicBlock, place: Place<'tcx>, diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs index d03794fe2d5..1b6d96e49f0 100644 --- a/compiler/rustc_mir_build/src/builder/matches/test.rs +++ b/compiler/rustc_mir_build/src/builder/matches/test.rs @@ -309,7 +309,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let actual = self.temp(usize_ty, test.span); // actual = len(place) - self.cfg.push_assign(block, source_info, actual, Rvalue::Len(place)); + let length_op = self.len_of_slice_or_array(block, place, test.span, source_info); + self.cfg.push_assign(block, source_info, actual, Rvalue::Use(length_op)); // expected = <N> let expected = self.push_usize(block, source_info, len); diff --git a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs index 9abb8343432..a4e4e30a8bb 100644 --- a/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs +++ b/compiler/rustc_mir_dataflow/src/impls/borrowed_locals.rs @@ -91,7 +91,6 @@ where | Rvalue::Use(..) | Rvalue::ThreadLocalRef(..) | Rvalue::Repeat(..) - | Rvalue::Len(..) | Rvalue::BinaryOp(..) | Rvalue::NullaryOp(..) | Rvalue::UnaryOp(..) diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs index 48718cad597..f38bb445824 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs @@ -413,7 +413,6 @@ impl<'a, 'tcx, F: Fn(Ty<'tcx>) -> bool> MoveDataBuilder<'a, 'tcx, F> { Rvalue::Ref(..) | Rvalue::RawPtr(..) | Rvalue::Discriminant(..) - | Rvalue::Len(..) | Rvalue::NullaryOp( NullOp::SizeOf | NullOp::AlignOf diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs index 4603c695ded..08316aaed3b 100644 --- a/compiler/rustc_mir_transform/src/coroutine.rs +++ b/compiler/rustc_mir_transform/src/coroutine.rs @@ -1340,14 +1340,13 @@ fn create_cases<'tcx>( } } - if operation == Operation::Resume { + if operation == Operation::Resume && point.resume_arg != CTX_ARG.into() { // Move the resume argument to the destination place of the `Yield` terminator - let resume_arg = CTX_ARG; statements.push(Statement::new( source_info, StatementKind::Assign(Box::new(( point.resume_arg, - Rvalue::Use(Operand::Move(resume_arg.into())), + Rvalue::Use(Operand::Move(CTX_ARG.into())), ))), )); } @@ -1439,7 +1438,10 @@ fn check_field_tys_sized<'tcx>( } impl<'tcx> crate::MirPass<'tcx> for StateTransform { + #[instrument(level = "debug", skip(self, tcx, body), ret)] fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { + debug!(def_id = ?body.source.def_id()); + let Some(old_yield_ty) = body.yield_ty() else { // This only applies to coroutines return; @@ -1518,31 +1520,7 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { cleanup_async_drops(body); } - // We also replace the resume argument and insert an `Assign`. - // This is needed because the resume argument `_2` might be live across a `yield`, in which - // case there is no `Assign` to it that the transform can turn into a store to the coroutine - // state. After the yield the slot in the coroutine state would then be uninitialized. - let resume_local = CTX_ARG; - let resume_ty = body.local_decls[resume_local].ty; - let old_resume_local = replace_local(resume_local, resume_ty, body, tcx); - - // When first entering the coroutine, move the resume argument into its old local - // (which is now a generator interior). - let source_info = SourceInfo::outermost(body.span); - let stmts = &mut body.basic_blocks_mut()[START_BLOCK].statements; - stmts.insert( - 0, - Statement::new( - source_info, - StatementKind::Assign(Box::new(( - old_resume_local.into(), - Rvalue::Use(Operand::Move(resume_local.into())), - ))), - ), - ); - let always_live_locals = always_storage_live_locals(body); - let movable = coroutine_kind.movability() == hir::Movability::Movable; let liveness_info = locals_live_across_suspend_points(tcx, body, &always_live_locals, movable); @@ -1583,6 +1561,21 @@ impl<'tcx> crate::MirPass<'tcx> for StateTransform { }; transform.visit_body(body); + // MIR parameters are not explicitly assigned-to when entering the MIR body. + // If we want to save their values inside the coroutine state, we need to do so explicitly. + let source_info = SourceInfo::outermost(body.span); + let args_iter = body.args_iter(); + body.basic_blocks.as_mut()[START_BLOCK].statements.splice( + 0..0, + args_iter.filter_map(|local| { + let (ty, variant_index, idx) = transform.remap[local]?; + let lhs = transform.make_field(variant_index, idx, ty); + let rhs = Rvalue::Use(Operand::Move(local.into())); + let assign = StatementKind::Assign(Box::new((lhs, rhs))); + Some(Statement::new(source_info, assign)) + }), + ); + // Update our MIR struct to reflect the changes we've made body.arg_count = 2; // self, resume arg body.spread_arg = None; diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs index fe53de31f75..5c984984d3c 100644 --- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs +++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs @@ -412,18 +412,6 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { state: &mut State<FlatSet<Scalar>>, ) -> ValueOrPlace<FlatSet<Scalar>> { let val = match rvalue { - Rvalue::Len(place) => { - let place_ty = place.ty(self.local_decls, self.tcx); - if let ty::Array(_, len) = place_ty.ty.kind() { - Const::Ty(self.tcx.types.usize, *len) - .try_eval_scalar(self.tcx, self.typing_env) - .map_or(FlatSet::Top, FlatSet::Elem) - } else if let [ProjectionElem::Deref] = place.projection[..] { - state.get_len(place.local.into(), &self.map) - } else { - FlatSet::Top - } - } Rvalue::Cast(CastKind::IntToInt | CastKind::IntToFloat, operand, ty) => { let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else { return ValueOrPlace::Value(FlatSet::Top); @@ -465,15 +453,23 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> { let (val, _overflow) = self.binary_op(state, *op, left, right); val } - Rvalue::UnaryOp(op, operand) => match self.eval_operand(operand, state) { - FlatSet::Elem(value) => self - .ecx - .unary_op(*op, &value) - .discard_err() - .map_or(FlatSet::Top, |val| self.wrap_immediate(*val)), - FlatSet::Bottom => FlatSet::Bottom, - FlatSet::Top => FlatSet::Top, - }, + Rvalue::UnaryOp(op, operand) => { + if let UnOp::PtrMetadata = op + && let Some(place) = operand.place() + && let Some(len) = self.map.find_len(place.as_ref()) + { + return ValueOrPlace::Place(len); + } + match self.eval_operand(operand, state) { + FlatSet::Elem(value) => self + .ecx + .unary_op(*op, &value) + .discard_err() + .map_or(FlatSet::Top, |val| self.wrap_immediate(*val)), + FlatSet::Bottom => FlatSet::Bottom, + FlatSet::Top => FlatSet::Top, + } + } Rvalue::NullaryOp(null_op, ty) => { let Ok(layout) = self.tcx.layout_of(self.typing_env.as_query_input(*ty)) else { return ValueOrPlace::Value(FlatSet::Top); diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs index 9ba2d274691..abd1cd4e35a 100644 --- a/compiler/rustc_mir_transform/src/dest_prop.rs +++ b/compiler/rustc_mir_transform/src/dest_prop.rs @@ -153,15 +153,7 @@ pub(super) struct DestinationPropagation; impl<'tcx> crate::MirPass<'tcx> for DestinationPropagation { fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - // For now, only run at MIR opt level 3. Two things need to be changed before this can be - // turned on by default: - // 1. Because of the overeager removal of storage statements, this can cause stack space - // regressions. This opt is not the place to fix this though, it's a more general - // problem in MIR. - // 2. Despite being an overall perf improvement, this still causes a 30% regression in - // keccak. We can temporarily fix this by bounding function size, but in the long term - // we should fix this by being smarter about invalidating analysis results. - sess.mir_opt_level() >= 3 + sess.mir_opt_level() >= 2 } #[tracing::instrument(level = "trace", skip(self, tcx, body))] @@ -567,13 +559,15 @@ fn save_as_intervals<'tcx>( // the written-to locals as live in the second half of the statement. // We also ensure that operands read by terminators conflict with writes by that terminator. // For instance a function call may read args after having written to the destination. - VisitPlacesWith(|place, ctxt| match DefUse::for_place(place, ctxt) { - DefUse::Def | DefUse::Use | DefUse::PartialWrite => { - if let Some(relevant) = relevant.shrink[place.local] { - values.insert(relevant, twostep); + VisitPlacesWith(|place: Place<'tcx>, ctxt| { + if let Some(relevant) = relevant.shrink[place.local] { + match DefUse::for_place(place, ctxt) { + DefUse::Def | DefUse::Use | DefUse::PartialWrite => { + values.insert(relevant, twostep); + } + DefUse::NonUse => {} } } - DefUse::NonUse => {} }) .visit_terminator(term, loc); @@ -588,15 +582,32 @@ fn save_as_intervals<'tcx>( twostep = TwoStepIndex::from_u32(twostep.as_u32() + 1); debug_assert_eq!(twostep, two_step_loc(loc, Effect::After)); append_at(&mut values, &state, twostep); - // Ensure we have a non-zero live range even for dead stores. This is done by marking - // all the written-to locals as live in the second half of the statement. - VisitPlacesWith(|place, ctxt| match DefUse::for_place(place, ctxt) { - DefUse::Def | DefUse::PartialWrite => { - if let Some(relevant) = relevant.shrink[place.local] { - values.insert(relevant, twostep); + // Like terminators, ensure we have a non-zero live range even for dead stores. + // Some rvalues interleave reads and writes, for instance `Rvalue::Aggregate`, see + // https://github.com/rust-lang/rust/issues/146383. By precaution, treat statements + // as behaving so by default. + // We make an exception for simple assignments `_a.stuff = {copy|move} _b.stuff`, + // as marking `_b` live here would prevent unification. + let is_simple_assignment = match stmt.kind { + StatementKind::Assign(box ( + lhs, + Rvalue::CopyForDeref(rhs) + | Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)), + )) => lhs.projection == rhs.projection, + _ => false, + }; + VisitPlacesWith(|place: Place<'tcx>, ctxt| { + if let Some(relevant) = relevant.shrink[place.local] { + match DefUse::for_place(place, ctxt) { + DefUse::Def | DefUse::PartialWrite => { + values.insert(relevant, twostep); + } + DefUse::Use if !is_simple_assignment => { + values.insert(relevant, twostep); + } + DefUse::Use | DefUse::NonUse => {} } } - DefUse::Use | DefUse::NonUse => {} }) .visit_statement(stmt, loc); diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index bf6aa800d20..30e68a3f650 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -200,8 +200,6 @@ enum Value<'tcx> { Projection(VnIndex, ProjectionElem<VnIndex, ()>), /// Discriminant of the given value. Discriminant(VnIndex), - /// Length of an array or slice. - Len(VnIndex), // Operations. NullaryOp(NullOp<'tcx>, Ty<'tcx>), @@ -477,11 +475,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { self.ecx.discriminant_for_variant(base.layout.ty, variant).discard_err()?; discr_value.into() } - Len(slice) => { - let slice = self.evaluated[slice].as_ref()?; - let len = slice.len(&self.ecx).discard_err()?; - ImmTy::from_uint(len, ty).into() - } NullaryOp(null_op, arg_ty) => { let arg_layout = self.ecx.layout_of(arg_ty).ok()?; if let NullOp::SizeOf | NullOp::AlignOf = null_op @@ -841,7 +834,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { } // Operations. - Rvalue::Len(ref mut place) => return self.simplify_len(place, location), Rvalue::Cast(ref mut kind, ref mut value, to) => { return self.simplify_cast(kind, value, to, location); } @@ -1049,7 +1041,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { if op == UnOp::PtrMetadata { let mut was_updated = false; loop { - match self.get(arg_index) { + arg_index = match self.get(arg_index) { // Pointer casts that preserve metadata, such as // `*const [i32]` <-> `*mut [i32]` <-> `*mut [f32]`. // It's critical that this not eliminate cases like @@ -1061,9 +1053,19 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Value::Cast { kind: CastKind::PtrToPtr, value: inner } if self.pointers_have_same_metadata(self.ty(*inner), arg_ty) => { - arg_index = *inner; - was_updated = true; - continue; + *inner + } + + // We have an unsizing cast, which assigns the length to wide pointer metadata. + Value::Cast { + kind: CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _), + value: from, + } if let Some(from) = self.ty(*from).builtin_deref(true) + && let ty::Array(_, len) = from.kind() + && let Some(to) = self.ty(arg_index).builtin_deref(true) + && let ty::Slice(..) = to.kind() => + { + return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); } // `&mut *p`, `&raw *p`, etc don't change metadata. @@ -1072,18 +1074,16 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { place.as_ref() && let Some(local_index) = self.locals[local] => { - arg_index = local_index; - was_updated = true; - continue; + local_index } - _ => { - if was_updated && let Some(op) = self.try_as_operand(arg_index, location) { - *arg_op = op; - } - break; - } - } + _ => break, + }; + was_updated = true; + } + + if was_updated && let Some(op) = self.try_as_operand(arg_index, location) { + *arg_op = op; } } @@ -1407,39 +1407,6 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { Some(self.insert(to, Value::Cast { kind, value })) } - fn simplify_len(&mut self, place: &mut Place<'tcx>, location: Location) -> Option<VnIndex> { - // Trivial case: we are fetching a statically known length. - let place_ty = place.ty(self.local_decls, self.tcx).ty; - if let ty::Array(_, len) = place_ty.kind() { - return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); - } - - let mut inner = self.simplify_place_value(place, location)?; - - // The length information is stored in the wide pointer. - // Reborrowing copies length information from one pointer to the other. - while let Value::Address { place: borrowed, .. } = self.get(inner) - && let [PlaceElem::Deref] = borrowed.projection[..] - && let Some(borrowed) = self.locals[borrowed.local] - { - inner = borrowed; - } - - // We have an unsizing cast, which assigns the length to wide pointer metadata. - if let Value::Cast { kind, value: from } = self.get(inner) - && let CastKind::PointerCoercion(ty::adjustment::PointerCoercion::Unsize, _) = kind - && let Some(from) = self.ty(*from).builtin_deref(true) - && let ty::Array(_, len) = from.kind() - && let Some(to) = self.ty(inner).builtin_deref(true) - && let ty::Slice(..) = to.kind() - { - return Some(self.insert_constant(Const::Ty(self.tcx.types.usize, *len))); - } - - // Fallback: a symbolic `Len`. - Some(self.insert(self.tcx.types.usize, Value::Len(inner))) - } - fn pointers_have_same_metadata(&self, left_ptr_ty: Ty<'tcx>, right_ptr_ty: Ty<'tcx>) -> bool { let left_meta_ty = left_ptr_ty.pointee_metadata_ty_or_projection(self.tcx); let right_meta_ty = right_ptr_ty.pointee_metadata_ty_or_projection(self.tcx); diff --git a/compiler/rustc_mir_transform/src/known_panics_lint.rs b/compiler/rustc_mir_transform/src/known_panics_lint.rs index 481c7941909..aaacc5866a2 100644 --- a/compiler/rustc_mir_transform/src/known_panics_lint.rs +++ b/compiler/rustc_mir_transform/src/known_panics_lint.rs @@ -441,7 +441,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { | Rvalue::Use(..) | Rvalue::CopyForDeref(..) | Rvalue::Repeat(..) - | Rvalue::Len(..) | Rvalue::Cast(..) | Rvalue::ShallowInitBox(..) | Rvalue::Discriminant(..) @@ -604,20 +603,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { return None; } - Len(place) => { - let len = if let ty::Array(_, n) = place.ty(self.local_decls(), self.tcx).ty.kind() - { - n.try_to_target_usize(self.tcx)? - } else { - match self.get_const(place)? { - Value::Immediate(src) => src.len(&self.ecx).discard_err()?, - Value::Aggregate { fields, .. } => fields.len() as u64, - Value::Uninit => return None, - } - }; - ImmTy::from_scalar(Scalar::from_target_usize(len, self), layout).into() - } - Ref(..) | RawPtr(..) => return None, NullaryOp(ref null_op, ty) => { diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 1663dfa744f..9ff7e0b5500 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -156,7 +156,6 @@ declare_passes! { mod match_branches : MatchBranchSimplification; mod mentioned_items : MentionedItems; mod multiple_return_terminators : MultipleReturnTerminators; - mod nrvo : RenameReturnPlace; mod post_drop_elaboration : CheckLiveDrops; mod prettify : ReorderBasicBlocks, ReorderLocals; mod promote_consts : PromoteTemps; @@ -715,7 +714,6 @@ pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' &jump_threading::JumpThreading, &early_otherwise_branch::EarlyOtherwiseBranch, &simplify_comparison_integral::SimplifyComparisonIntegral, - &dest_prop::DestinationPropagation, &o1(simplify_branches::SimplifyConstCondition::Final), &o1(remove_noop_landing_pads::RemoveNoopLandingPads), &o1(simplify::SimplifyCfg::Final), @@ -723,7 +721,7 @@ pub(crate) fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<' &strip_debuginfo::StripDebugInfo, ©_prop::CopyProp, &dead_store_elimination::DeadStoreElimination::Final, - &nrvo::RenameReturnPlace, + &dest_prop::DestinationPropagation, &simplify::SimplifyLocals::Final, &multiple_return_terminators::MultipleReturnTerminators, &large_enums::EnumSizeOpt { discrepancy: 128 }, diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs deleted file mode 100644 index 965002aae04..00000000000 --- a/compiler/rustc_mir_transform/src/nrvo.rs +++ /dev/null @@ -1,234 +0,0 @@ -//! See the docs for [`RenameReturnPlace`]. - -use rustc_hir::Mutability; -use rustc_index::bit_set::DenseBitSet; -use rustc_middle::bug; -use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor}; -use rustc_middle::mir::{self, BasicBlock, Local, Location}; -use rustc_middle::ty::TyCtxt; -use tracing::{debug, trace}; - -/// This pass looks for MIR that always copies the same local into the return place and eliminates -/// the copy by renaming all uses of that local to `_0`. -/// -/// This allows LLVM to perform an optimization similar to the named return value optimization -/// (NRVO) that is guaranteed in C++. This avoids a stack allocation and `memcpy` for the -/// relatively common pattern of allocating a buffer on the stack, mutating it, and returning it by -/// value like so: -/// -/// ```rust -/// fn foo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { -/// let mut buf = [0; 1024]; -/// init(&mut buf); -/// buf -/// } -/// ``` -/// -/// For now, this pass is very simple and only capable of eliminating a single copy. A more general -/// version of copy propagation, such as the one based on non-overlapping live ranges in [#47954] and -/// [#71003], could yield even more benefits. -/// -/// [#47954]: https://github.com/rust-lang/rust/pull/47954 -/// [#71003]: https://github.com/rust-lang/rust/pull/71003 -pub(super) struct RenameReturnPlace; - -impl<'tcx> crate::MirPass<'tcx> for RenameReturnPlace { - fn is_enabled(&self, sess: &rustc_session::Session) -> bool { - // unsound: #111005 - sess.mir_opt_level() > 0 && sess.opts.unstable_opts.unsound_mir_opts - } - - fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) { - let def_id = body.source.def_id(); - let Some(returned_local) = local_eligible_for_nrvo(body) else { - debug!("`{:?}` was ineligible for NRVO", def_id); - return; - }; - - debug!( - "`{:?}` was eligible for NRVO, making {:?} the return place", - def_id, returned_local - ); - - RenameToReturnPlace { tcx, to_rename: returned_local }.visit_body_preserves_cfg(body); - - // Clean up the `NOP`s we inserted for statements made useless by our renaming. - for block_data in body.basic_blocks.as_mut_preserves_cfg() { - block_data.statements.retain(|stmt| stmt.kind != mir::StatementKind::Nop); - } - - // Overwrite the debuginfo of `_0` with that of the renamed local. - let (renamed_decl, ret_decl) = - body.local_decls.pick2_mut(returned_local, mir::RETURN_PLACE); - - // Sometimes, the return place is assigned a local of a different but coercible type, for - // example `&mut T` instead of `&T`. Overwriting the `LocalInfo` for the return place means - // its type may no longer match the return type of its function. This doesn't cause a - // problem in codegen because these two types are layout-compatible, but may be unexpected. - debug!("_0: {:?} = {:?}: {:?}", ret_decl.ty, returned_local, renamed_decl.ty); - ret_decl.clone_from(renamed_decl); - - // The return place is always mutable. - ret_decl.mutability = Mutability::Mut; - } - - fn is_required(&self) -> bool { - false - } -} - -/// MIR that is eligible for the NRVO must fulfill two conditions: -/// 1. The return place must not be read prior to the `Return` terminator. -/// 2. A simple assignment of a whole local to the return place (e.g., `_0 = _1`) must be the -/// only definition of the return place reaching the `Return` terminator. -/// -/// If the MIR fulfills both these conditions, this function returns the `Local` that is assigned -/// to the return place along all possible paths through the control-flow graph. -fn local_eligible_for_nrvo(body: &mir::Body<'_>) -> Option<Local> { - if IsReturnPlaceRead::run(body) { - return None; - } - - let mut copied_to_return_place = None; - for block in body.basic_blocks.indices() { - // Look for blocks with a `Return` terminator. - if !matches!(body[block].terminator().kind, mir::TerminatorKind::Return) { - continue; - } - - // Look for an assignment of a single local to the return place prior to the `Return`. - let returned_local = find_local_assigned_to_return_place(block, body)?; - match body.local_kind(returned_local) { - // FIXME: Can we do this for arguments as well? - mir::LocalKind::Arg => return None, - - mir::LocalKind::ReturnPointer => bug!("Return place was assigned to itself?"), - mir::LocalKind::Temp => {} - } - - // If multiple different locals are copied to the return place. We can't pick a - // single one to rename. - if copied_to_return_place.is_some_and(|old| old != returned_local) { - return None; - } - - copied_to_return_place = Some(returned_local); - } - - copied_to_return_place -} - -fn find_local_assigned_to_return_place(start: BasicBlock, body: &mir::Body<'_>) -> Option<Local> { - let mut block = start; - let mut seen = DenseBitSet::new_empty(body.basic_blocks.len()); - - // Iterate as long as `block` has exactly one predecessor that we have not yet visited. - while seen.insert(block) { - trace!("Looking for assignments to `_0` in {:?}", block); - - let local = body[block].statements.iter().rev().find_map(as_local_assigned_to_return_place); - if local.is_some() { - return local; - } - - match body.basic_blocks.predecessors()[block].as_slice() { - &[pred] => block = pred, - _ => return None, - } - } - - None -} - -// If this statement is an assignment of an unprojected local to the return place, -// return that local. -fn as_local_assigned_to_return_place(stmt: &mir::Statement<'_>) -> Option<Local> { - if let mir::StatementKind::Assign(box (lhs, rhs)) = &stmt.kind { - if lhs.as_local() == Some(mir::RETURN_PLACE) { - if let mir::Rvalue::Use(mir::Operand::Copy(rhs) | mir::Operand::Move(rhs)) = rhs { - return rhs.as_local(); - } - } - } - - None -} - -struct RenameToReturnPlace<'tcx> { - to_rename: Local, - tcx: TyCtxt<'tcx>, -} - -/// Replaces all uses of `self.to_rename` with `_0`. -impl<'tcx> MutVisitor<'tcx> for RenameToReturnPlace<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_statement(&mut self, stmt: &mut mir::Statement<'tcx>, loc: Location) { - // Remove assignments of the local being replaced to the return place, since it is now the - // return place: - // _0 = _1 - if as_local_assigned_to_return_place(stmt) == Some(self.to_rename) { - stmt.kind = mir::StatementKind::Nop; - return; - } - - // Remove storage annotations for the local being replaced: - // StorageLive(_1) - if let mir::StatementKind::StorageLive(local) | mir::StatementKind::StorageDead(local) = - stmt.kind - { - if local == self.to_rename { - stmt.kind = mir::StatementKind::Nop; - return; - } - } - - self.super_statement(stmt, loc) - } - - fn visit_terminator(&mut self, terminator: &mut mir::Terminator<'tcx>, loc: Location) { - // Ignore the implicit "use" of the return place in a `Return` statement. - if let mir::TerminatorKind::Return = terminator.kind { - return; - } - - self.super_terminator(terminator, loc); - } - - fn visit_local(&mut self, l: &mut Local, ctxt: PlaceContext, _: Location) { - if *l == mir::RETURN_PLACE { - assert_eq!(ctxt, PlaceContext::NonUse(NonUseContext::VarDebugInfo)); - } else if *l == self.to_rename { - *l = mir::RETURN_PLACE; - } - } -} - -struct IsReturnPlaceRead(bool); - -impl IsReturnPlaceRead { - fn run(body: &mir::Body<'_>) -> bool { - let mut vis = IsReturnPlaceRead(false); - vis.visit_body(body); - vis.0 - } -} - -impl<'tcx> Visitor<'tcx> for IsReturnPlaceRead { - fn visit_local(&mut self, l: Local, ctxt: PlaceContext, _: Location) { - if l == mir::RETURN_PLACE && ctxt.is_use() && !ctxt.is_place_assignment() { - self.0 = true; - } - } - - fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, loc: Location) { - // Ignore the implicit "use" of the return place in a `Return` statement. - if let mir::TerminatorKind::Return = terminator.kind { - return; - } - - self.super_terminator(terminator, loc); - } -} diff --git a/compiler/rustc_mir_transform/src/promote_consts.rs b/compiler/rustc_mir_transform/src/promote_consts.rs index 9ea2eb4f25d..a0b0c8c990f 100644 --- a/compiler/rustc_mir_transform/src/promote_consts.rs +++ b/compiler/rustc_mir_transform/src/promote_consts.rs @@ -437,9 +437,7 @@ impl<'tcx> Validator<'_, 'tcx> { self.validate_operand(op)? } - Rvalue::Discriminant(place) | Rvalue::Len(place) => { - self.validate_place(place.as_ref())? - } + Rvalue::Discriminant(place) => self.validate_place(place.as_ref())?, Rvalue::ThreadLocalRef(_) => return Err(Unpromotable), diff --git a/compiler/rustc_mir_transform/src/validate.rs b/compiler/rustc_mir_transform/src/validate.rs index 99e4782e470..c8a9a88dc3f 100644 --- a/compiler/rustc_mir_transform/src/validate.rs +++ b/compiler/rustc_mir_transform/src/validate.rs @@ -1064,14 +1064,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } } Rvalue::Ref(..) => {} - Rvalue::Len(p) => { - let pty = p.ty(&self.body.local_decls, self.tcx).ty; - check_kinds!( - pty, - "Cannot compute length of non-array type {:?}", - ty::Array(..) | ty::Slice(..) - ); - } Rvalue::BinaryOp(op, vals) => { use BinOp::*; let a = vals.0.ty(&self.body.local_decls, self.tcx); diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index 72cd75f6d89..f83cf645f82 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -189,6 +189,10 @@ parse_dotdotdot = unexpected token: `...` parse_dotdotdot_rest_pattern = unexpected `...` .label = not a valid pattern .suggestion = for a rest pattern, use `..` instead of `...` + .note = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list + +parse_dotdotdot_rest_type = unexpected `...` + .note = only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list parse_double_colon_in_bound = expected `:` followed by trait or lifetime .suggestion = use single colon diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 00ca5acd84d..1abeee6fe43 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2723,7 +2723,9 @@ pub(crate) struct DotDotDotRestPattern { #[label] pub span: Span, #[suggestion(style = "verbose", code = "", applicability = "machine-applicable")] - pub suggestion: Span, + pub suggestion: Option<Span>, + #[note] + pub var_args: Option<()>, } #[derive(Diagnostic)] @@ -3031,6 +3033,14 @@ pub(crate) struct NestedCVariadicType { } #[derive(Diagnostic)] +#[diag(parse_dotdotdot_rest_type)] +#[note] +pub(crate) struct InvalidCVariadicType { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] #[diag(parse_invalid_dyn_keyword)] #[help] pub(crate) struct InvalidDynKeyword { diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index c4d30b3d328..fda19d62bc7 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -756,7 +756,7 @@ impl<'a> Parser<'a> { self.bump(); // `..` PatKind::Rest } else if self.check(exp!(DotDotDot)) && !self.is_pat_range_end_start(1) { - self.recover_dotdotdot_rest_pat(lo) + self.recover_dotdotdot_rest_pat(lo, expected) } else if let Some(form) = self.parse_range_end() { self.parse_pat_range_to(form)? // `..=X`, `...X`, or `..X`. } else if self.eat(exp!(Bang)) { @@ -886,16 +886,27 @@ impl<'a> Parser<'a> { /// Recover from a typoed `...` pattern that was encountered /// Ref: Issue #70388 - fn recover_dotdotdot_rest_pat(&mut self, lo: Span) -> PatKind { + fn recover_dotdotdot_rest_pat(&mut self, lo: Span, expected: Option<Expected>) -> PatKind { // A typoed rest pattern `...`. self.bump(); // `...` - // The user probably mistook `...` for a rest pattern `..`. - self.dcx().emit_err(DotDotDotRestPattern { - span: lo, - suggestion: lo.with_lo(lo.hi() - BytePos(1)), - }); - PatKind::Rest + if let Some(Expected::ParameterName) = expected { + // We have `...` in a closure argument, likely meant to be var-arg, which aren't + // supported in closures (#146489). + PatKind::Err(self.dcx().emit_err(DotDotDotRestPattern { + span: lo, + suggestion: None, + var_args: Some(()), + })) + } else { + // The user probably mistook `...` for a rest pattern `..`. + self.dcx().emit_err(DotDotDotRestPattern { + span: lo, + suggestion: Some(lo.with_lo(lo.hi() - BytePos(1))), + var_args: None, + }); + PatKind::Rest + } } /// Try to recover the more general form `intersect ::= $pat_lhs @ $pat_rhs`. diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 23aaafac934..65347496599 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -15,8 +15,8 @@ use super::{Parser, PathStyle, SeqSep, TokenType, Trailing}; use crate::errors::{ self, AttributeOnEmptyType, AttributeOnType, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType, FnPtrWithGenerics, FnPtrWithGenericsSugg, - HelpUseLatestEdition, InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, - NestedCVariadicType, ReturnTypesUseThinArrow, + HelpUseLatestEdition, InvalidCVariadicType, InvalidDynKeyword, LifetimeAfterMut, + NeedPlusAfterTraitObjectLifetime, NestedCVariadicType, ReturnTypesUseThinArrow, }; use crate::parser::item::FrontMatterParsingMode; use crate::parser::{FnContext, FnParseMode}; @@ -106,6 +106,15 @@ fn can_begin_dyn_bound_in_edition_2015(t: &Token) -> bool { impl<'a> Parser<'a> { /// Parses a type. pub fn parse_ty(&mut self) -> PResult<'a, Box<Ty>> { + if self.token == token::DotDotDot { + // We special case this so that we don't talk about "nested C-variadics" in types. + // We still pass in `AllowCVariadic::No` so that `parse_ty_common` can complain about + // things like `Vec<...>`. + let span = self.token.span; + self.bump(); + let kind = TyKind::Err(self.dcx().emit_err(InvalidCVariadicType { span })); + return Ok(self.mk_ty(span, kind)); + } // Make sure deeply nested types don't overflow the stack. ensure_sufficient_stack(|| { self.parse_ty_common( diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2562d2e0b83..60f575cb844 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -276,6 +276,8 @@ impl<'tcx> CheckAttrVisitor<'tcx> { | AttributeKind::PatternComplexityLimit { .. } | AttributeKind::NoCore { .. } | AttributeKind::NoStd { .. } + | AttributeKind::ObjcClass { .. } + | AttributeKind::ObjcSelector { .. } ) => { /* do nothing */ } Attribute::Unparsed(attr_item) => { style = Some(attr_item.style); diff --git a/compiler/rustc_public/src/unstable/convert/stable/mir.rs b/compiler/rustc_public/src/unstable/convert/stable/mir.rs index be8ee80bed3..b10af6526ea 100644 --- a/compiler/rustc_public/src/unstable/convert/stable/mir.rs +++ b/compiler/rustc_public/src/unstable/convert/stable/mir.rs @@ -215,7 +215,6 @@ impl<'tcx> Stable<'tcx> for mir::Rvalue<'tcx> { mutability.stable(tables, cx), place.stable(tables, cx), ), - Len(place) => crate::mir::Rvalue::Len(place.stable(tables, cx)), Cast(cast_kind, op, ty) => crate::mir::Rvalue::Cast( cast_kind.stable(tables, cx), op.stable(tables, cx), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index cdb0b5b58da..4fef65f46b1 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1413,6 +1413,7 @@ symbols! { mir_call, mir_cast_ptr_to_ptr, mir_cast_transmute, + mir_cast_unsize, mir_checked, mir_copy_for_deref, mir_debuginfo, @@ -1917,6 +1918,8 @@ symbols! { rustc_no_mir_inline, rustc_nonnull_optimization_guaranteed, rustc_nounwind, + rustc_objc_class, + rustc_objc_selector, rustc_object_lifetime_default, rustc_on_unimplemented, rustc_outlives, diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs index edab530590b..75283dc4ffa 100644 --- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs +++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs @@ -4,11 +4,12 @@ use std::path::PathBuf; use rustc_errors::codes::*; use rustc_errors::{Diag, IntoDiagArg}; -use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Namespace, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; -use rustc_hir::{Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource}; +use rustc_hir::{ + self as hir, Body, Closure, Expr, ExprKind, FnRetTy, HirId, LetStmt, LocalSource, PatKind, +}; use rustc_middle::bug; use rustc_middle::hir::nested_filter; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; @@ -512,7 +513,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { type_name: ty_to_string(self, ty, def_id), }); } - InferSourceKind::ClosureArg { insert_span, ty } => { + InferSourceKind::ClosureArg { insert_span, ty, .. } => { infer_subdiags.push(SourceKindSubdiag::LetLike { span: insert_span, name: String::new(), @@ -652,6 +653,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { }), }; *err.long_ty_path() = long_ty_path; + if let InferSourceKind::ClosureArg { kind: PatKind::Err(_), .. } = kind { + // We will have already emitted an error about this pattern. + err.downgrade_to_delayed_bug(); + } err } } @@ -673,6 +678,7 @@ enum InferSourceKind<'tcx> { ClosureArg { insert_span: Span, ty: Ty<'tcx>, + kind: PatKind<'tcx>, }, GenericArg { insert_span: Span, @@ -1197,6 +1203,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> { kind: InferSourceKind::ClosureArg { insert_span: param.pat.span.shrink_to_hi(), ty: param_ty, + kind: param.pat.kind, }, }) } diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs index 393f458bea2..4c25882daa9 100644 --- a/compiler/rustc_trait_selection/src/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -1,15 +1,14 @@ //! Miscellaneous type-system utilities that are too small to deserve their own modules. -use std::assert_matches::assert_matches; - use hir::LangItem; use rustc_ast::Mutability; use rustc_hir as hir; use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt}; use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt, TypeVisitableExt, TypingMode}; +use rustc_span::sym; use crate::regions::InferCtxtRegionExt; -use crate::traits::{self, FulfillmentError, ObligationCause}; +use crate::traits::{self, FulfillmentError, Obligation, ObligationCause}; pub enum CopyImplementationError<'tcx> { InfringingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>), @@ -98,10 +97,9 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, self_type: Ty<'tcx>, - lang_item: LangItem, parent_cause: ObligationCause<'tcx>, ) -> Result<(), ConstParamTyImplementationError<'tcx>> { - assert_matches!(lang_item, LangItem::ConstParamTy | LangItem::UnsizedConstParamTy); + let mut need_unstable_feature_bound = false; let inner_tys: Vec<_> = match *self_type.kind() { // Trivially okay as these types are all: @@ -112,18 +110,14 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( // Handle types gated under `feature(unsized_const_params)` // FIXME(unsized_const_params): Make `const N: [u8]` work then forbid references - ty::Slice(inner_ty) | ty::Ref(_, inner_ty, Mutability::Not) - if lang_item == LangItem::UnsizedConstParamTy => - { + ty::Slice(inner_ty) | ty::Ref(_, inner_ty, Mutability::Not) => { + need_unstable_feature_bound = true; vec![inner_ty] } - ty::Str if lang_item == LangItem::UnsizedConstParamTy => { + ty::Str => { + need_unstable_feature_bound = true; vec![Ty::new_slice(tcx, tcx.types.u8)] } - ty::Str | ty::Slice(..) | ty::Ref(_, _, Mutability::Not) => { - return Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired); - } - ty::Array(inner_ty, _) => vec![inner_ty], // `str` morally acts like a newtype around `[u8]` @@ -137,7 +131,7 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( adt, args, parent_cause.clone(), - lang_item, + LangItem::ConstParamTy, ) .map_err(ConstParamTyImplementationError::InfrigingFields)?; @@ -153,11 +147,25 @@ pub fn type_allowed_to_implement_const_param_ty<'tcx>( let infcx = tcx.infer_ctxt().build(TypingMode::non_body_analysis()); let ocx = traits::ObligationCtxt::new_with_diagnostics(&infcx); + // Make sure impls certain types are gated with #[unstable_feature_bound(unsized_const_params)] + if need_unstable_feature_bound { + ocx.register_obligation(Obligation::new( + tcx, + parent_cause.clone(), + param_env, + ty::ClauseKind::UnstableFeature(sym::unsized_const_params), + )); + + if !ocx.select_all_or_error().is_empty() { + return Err(ConstParamTyImplementationError::UnsizedConstParamsFeatureRequired); + } + } + ocx.register_bound( parent_cause.clone(), param_env, inner_ty, - tcx.require_lang_item(lang_item, parent_cause.span), + tcx.require_lang_item(LangItem::ConstParamTy, parent_cause.span), ); let errors = ocx.select_all_or_error(); diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index ec9b774c308..21486651b0b 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -271,7 +271,6 @@ impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { /// # Examples /// /// ``` - /// #![feature(btree_entry_insert)] /// use std::collections::BTreeMap; /// /// let mut map: BTreeMap<&str, String> = BTreeMap::new(); @@ -280,7 +279,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { /// assert_eq!(entry.key(), &"poneyland"); /// ``` #[inline] - #[unstable(feature = "btree_entry_insert", issue = "65225")] + #[stable(feature = "btree_entry_insert", since = "CURRENT_RUSTC_VERSION")] pub fn insert_entry(self, value: V) -> OccupiedEntry<'a, K, V, A> { match self { Occupied(mut entry) => { @@ -379,7 +378,6 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> { /// # Examples /// /// ``` - /// #![feature(btree_entry_insert)] /// use std::collections::BTreeMap; /// use std::collections::btree_map::Entry; /// @@ -391,7 +389,7 @@ impl<'a, K: Ord, V, A: Allocator + Clone> VacantEntry<'a, K, V, A> { /// } /// assert_eq!(map["poneyland"], 37); /// ``` - #[unstable(feature = "btree_entry_insert", issue = "65225")] + #[stable(feature = "btree_entry_insert", since = "CURRENT_RUSTC_VERSION")] pub fn insert_entry(mut self, value: V) -> OccupiedEntry<'a, K, V, A> { let handle = match self.handle { None => { diff --git a/library/alloc/src/vec/peek_mut.rs b/library/alloc/src/vec/peek_mut.rs index c0dd941ed39..caeaf2799d7 100644 --- a/library/alloc/src/vec/peek_mut.rs +++ b/library/alloc/src/vec/peek_mut.rs @@ -29,9 +29,9 @@ impl<'a, T> PeekMut<'a, T> { /// Removes the peeked value from the vector and returns it. #[unstable(feature = "vec_peek_mut", issue = "122742")] - pub fn pop(self) -> T { + pub fn pop(this: Self) -> T { // SAFETY: PeekMut is only constructed if the vec is non-empty - unsafe { self.vec.pop().unwrap_unchecked() } + unsafe { this.vec.pop().unwrap_unchecked() } } } diff --git a/library/alloctests/tests/vec.rs b/library/alloctests/tests/vec.rs index 00f640cd17e..404eb49e1ea 100644 --- a/library/alloctests/tests/vec.rs +++ b/library/alloctests/tests/vec.rs @@ -15,7 +15,7 @@ use std::ops::Bound::*; use std::panic::{AssertUnwindSafe, catch_unwind}; use std::rc::Rc; use std::sync::atomic::{AtomicU32, Ordering}; -use std::vec::{Drain, IntoIter}; +use std::vec::{Drain, IntoIter, PeekMut}; use crate::testing::macros::struct_with_counted_drop; @@ -2647,7 +2647,7 @@ fn test_peek_mut() { assert_eq!(*p, 2); *p = 0; assert_eq!(*p, 0); - p.pop(); + PeekMut::pop(p); assert_eq!(vec.len(), 1); } else { unreachable!() diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index d14419a23a1..d713e575b58 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -472,6 +472,11 @@ impl<T: Copy> SpecArrayClone for T { // The Default impls cannot be done with const generics because `[T; 0]` doesn't // require Default to be implemented, and having different impl blocks for // different numbers isn't supported yet. +// +// Trying to improve the `[T; 0]` situation has proven to be difficult. +// Please see these issues for more context on past attempts and crater runs: +// - https://github.com/rust-lang/rust/issues/61415 +// - https://github.com/rust-lang/rust/pull/145457 macro_rules! array_impl_default { {$n:expr, $t:ident $($ts:ident)*} => { diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 94536f25b41..95896ab1441 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -334,9 +334,8 @@ pub macro PartialEq($item:item) { #[doc(alias = "!=")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Eq"] -#[const_trait] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] -pub trait Eq: [const] PartialEq<Self> + PointeeSized { +pub const trait Eq: [const] PartialEq<Self> + PointeeSized { // this method is used solely by `impl Eq or #[derive(Eq)]` to assert that every component of a // type implements `Eq` itself. The current deriving infrastructure means doing this assertion // without using a method on this trait is nearly impossible. @@ -966,9 +965,8 @@ impl<T: Clone> Clone for Reverse<T> { #[doc(alias = ">=")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_diagnostic_item = "Ord"] -#[const_trait] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] -pub trait Ord: [const] Eq + [const] PartialOrd<Self> + PointeeSized { +pub const trait Ord: [const] Eq + [const] PartialOrd<Self> + PointeeSized { /// This method returns an [`Ordering`] between `self` and `other`. /// /// By convention, `self.cmp(&other)` returns the ordering matching the expression @@ -1352,9 +1350,8 @@ pub macro Ord($item:item) { )] #[rustc_diagnostic_item = "PartialOrd"] #[allow(multiple_supertrait_upcastable)] // FIXME(sized_hierarchy): remove this -#[const_trait] #[rustc_const_unstable(feature = "const_cmp", issue = "143800")] -pub trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized { +pub const trait PartialOrd<Rhs: PointeeSized = Self>: PartialEq<Rhs> + PointeeSized { /// This method returns an ordering between `self` and `other` values if one exists. /// /// # Examples diff --git a/library/core/src/intrinsics/mir.rs b/library/core/src/intrinsics/mir.rs index 55dcf7cd47e..a800ef1cb93 100644 --- a/library/core/src/intrinsics/mir.rs +++ b/library/core/src/intrinsics/mir.rs @@ -233,7 +233,8 @@ //! //! - Operands implicitly convert to `Use` rvalues. //! - `&`, `&mut`, `addr_of!`, and `addr_of_mut!` all work to create their associated rvalue. -//! - [`Discriminant`], [`Len`], and [`CopyForDeref`] have associated functions. +//! - [`CopyForDeref`], [`CastTransmute`], [`CastPtrToPtr`], [`CastUnsize`], and [`Discriminant`] +//! 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`]. @@ -401,7 +402,6 @@ define!("mir_storage_dead", fn StorageDead<T>(local: T)); define!("mir_assume", fn Assume(operand: bool)); 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_ptr_metadata", fn PtrMetadata<P: ?Sized>(place: *const P) -> <P as ::core::ptr::Pointee>::Metadata @@ -492,6 +492,13 @@ define!( fn CastPtrToPtr<T, U>(operand: T) -> U ); define!( + "mir_cast_unsize", + /// Emits a `CastKind::PointerCoercion(Unsize)` cast. + /// + /// This allows bypassing normal validation to generate strange casts. + fn CastUnsize<T, U>(operand: T) -> U +); +define!( "mir_make_place", #[doc(hidden)] fn __internal_make_place<T>(place: T) -> *mut T diff --git a/library/core/src/iter/sources/repeat.rs b/library/core/src/iter/sources/repeat.rs index c4f5a483e5c..4bcd5b16aea 100644 --- a/library/core/src/iter/sources/repeat.rs +++ b/library/core/src/iter/sources/repeat.rs @@ -9,7 +9,7 @@ use crate::num::NonZero; /// [`Iterator::take()`], in order to make them finite. /// /// Use [`str::repeat()`] instead of this function if you just want to repeat -/// a char/string `n`th times. +/// a char/string `n` times. /// /// If the element type of the iterator you need does not implement `Clone`, /// or if you do not want to keep the repeated element in memory, you can @@ -98,11 +98,12 @@ impl<A: Clone> Iterator for Repeat<A> { } fn last(self) -> Option<A> { - loop {} + Some(self.element) } + #[track_caller] fn count(self) -> usize { - loop {} + panic!("iterator is infinite"); } } diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 86a68e18b0a..5d52bfb1b12 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -313,6 +313,7 @@ pub mod io; pub mod iter; pub mod net; pub mod option; +pub mod os; pub mod panic; pub mod panicking; #[unstable(feature = "pattern_type_macro", issue = "123646")] diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index d03d7a43469..1c100312a9a 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -1083,7 +1083,7 @@ pub trait Tuple {} // We name this differently than the derive macro so that the `adt_const_params` can // be used independently of `unsized_const_params` without requiring a full path // to the derive macro every time it is used. This should be renamed on stabilization. -pub trait ConstParamTy_: UnsizedConstParamTy + StructuralPartialEq + Eq {} +pub trait ConstParamTy_: StructuralPartialEq + Eq {} /// Derive macro generating an impl of the trait `ConstParamTy`. #[rustc_builtin_macro] @@ -1093,23 +1093,6 @@ pub macro ConstParamTy($item:item) { /* compiler built-in */ } -#[lang = "unsized_const_param_ty"] -#[unstable(feature = "unsized_const_params", issue = "95174")] -#[diagnostic::on_unimplemented(message = "`{Self}` can't be used as a const parameter type")] -/// A marker for types which can be used as types of `const` generic parameters. -/// -/// Equivalent to [`ConstParamTy_`] except that this is used by -/// the `unsized_const_params` to allow for fake unstable impls. -pub trait UnsizedConstParamTy: StructuralPartialEq + Eq {} - -/// Derive macro generating an impl of the trait `ConstParamTy`. -#[rustc_builtin_macro] -#[allow_internal_unstable(unsized_const_params)] -#[unstable(feature = "unsized_const_params", issue = "95174")] -pub macro UnsizedConstParamTy($item:item) { - /* compiler built-in */ -} - // FIXME(adt_const_params): handle `ty::FnDef`/`ty::Closure` marker_impls! { #[unstable(feature = "adt_const_params", issue = "95174")] @@ -1124,17 +1107,11 @@ marker_impls! { marker_impls! { #[unstable(feature = "unsized_const_params", issue = "95174")] - UnsizedConstParamTy for - usize, u8, u16, u32, u64, u128, - isize, i8, i16, i32, i64, i128, - bool, - char, - (), - {T: UnsizedConstParamTy, const N: usize} [T; N], - + #[unstable_feature_bound(unsized_const_params)] + ConstParamTy_ for str, - {T: UnsizedConstParamTy} [T], - {T: UnsizedConstParamTy + ?Sized} &T, + {T: ConstParamTy_} [T], + {T: ConstParamTy_ + ?Sized} &T, } /// A common trait implemented by all function pointers. diff --git a/library/core/src/mem/transmutability.rs b/library/core/src/mem/transmutability.rs index 782b826448a..f36cb8cddb8 100644 --- a/library/core/src/mem/transmutability.rs +++ b/library/core/src/mem/transmutability.rs @@ -1,4 +1,4 @@ -use crate::marker::{ConstParamTy_, UnsizedConstParamTy}; +use crate::marker::ConstParamTy_; /// Marks that `Src` is transmutable into `Self`. /// @@ -83,6 +83,7 @@ use crate::marker::{ConstParamTy_, UnsizedConstParamTy}; /// Furthermore, stability does not imply portability. For example, the size of /// `usize` is stable, but not portable. #[unstable(feature = "transmutability", issue = "99571")] +#[unstable_feature_bound(transmutability)] #[lang = "transmute_trait"] #[rustc_deny_explicit_impl] #[rustc_do_not_implement_via_object] @@ -288,9 +289,8 @@ pub struct Assume { } #[unstable(feature = "transmutability", issue = "99571")] +#[unstable_feature_bound(transmutability)] impl ConstParamTy_ for Assume {} -#[unstable(feature = "transmutability", issue = "99571")] -impl UnsizedConstParamTy for Assume {} impl Assume { /// With this, [`TransmuteFrom`] does not assume you have ensured any safety diff --git a/library/core/src/os/darwin/mod.rs b/library/core/src/os/darwin/mod.rs new file mode 100644 index 00000000000..8426d82b8ce --- /dev/null +++ b/library/core/src/os/darwin/mod.rs @@ -0,0 +1,19 @@ +//! Platform-specific extensions to `core` for Darwin / Apple platforms. +//! +//! This is available on the following operating systems: +//! - macOS +//! - iOS +//! - tvOS +//! - watchOS +//! - visionOS +//! +//! Note: This module is called "Darwin" as that's the name of the underlying +//! core OS of the above operating systems, but it should not be confused with +//! the `-darwin` suffix in the `x86_64-apple-darwin` and +//! `aarch64-apple-darwin` target names, which are mostly named that way for +//! legacy reasons. + +#![unstable(feature = "darwin_objc", issue = "145496")] +#![doc(cfg(target_vendor = "apple"))] + +pub mod objc; diff --git a/library/core/src/os/darwin/objc.rs b/library/core/src/os/darwin/objc.rs new file mode 100644 index 00000000000..928cb54e82c --- /dev/null +++ b/library/core/src/os/darwin/objc.rs @@ -0,0 +1,113 @@ +//! Defines types and macros for Objective-C interoperability. + +#![unstable(feature = "darwin_objc", issue = "145496")] +#![allow(nonstandard_style)] + +use crate::fmt; + +/// Equivalent to Objective-C’s `struct objc_class` type. +#[cfg_attr(not(doc), repr(u8))] // An implementation detail we don't want to show up in rustdoc +pub enum objc_class { + #[unstable( + feature = "objc_class_variant", + reason = "temporary implementation detail", + issue = "none" + )] + #[doc(hidden)] + __variant1, + #[unstable( + feature = "objc_class_variant", + reason = "temporary implementation detail", + issue = "none" + )] + #[doc(hidden)] + __variant2, +} + +impl fmt::Debug for objc_class { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("objc_class").finish() + } +} + +/// Equivalent to Objective-C’s `struct objc_selector` type. +#[cfg_attr(not(doc), repr(u8))] // An implementation detail we don't want to show up in rustdoc +pub enum objc_selector { + #[unstable( + feature = "objc_selector_variant", + reason = "temporary implementation detail", + issue = "none" + )] + #[doc(hidden)] + __variant1, + #[unstable( + feature = "objc_selector_variant", + reason = "temporary implementation detail", + issue = "none" + )] + #[doc(hidden)] + __variant2, +} + +impl fmt::Debug for objc_selector { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("objc_selector").finish() + } +} + +/// Equivalent to Objective-C’s `Class` type. +pub type Class = *mut objc_class; + +/// Equivalent to Objective-C’s `SEL` type. +pub type SEL = *mut objc_selector; + +/// Gets a reference to an Objective-C class. +/// +/// This macro will yield an expression of type [`Class`] for the given class name string literal. +/// +/// # Example +/// +/// ```no_run +/// #![feature(darwin_objc)] +/// use core::os::darwin::objc; +/// +/// let string_class = objc::class!("NSString"); +/// ``` +#[allow_internal_unstable(rustc_attrs)] +pub macro class($classname:expr) {{ + // Since static Objective-C class references actually end up with multiple definitions + // across dylib boundaries, we only expose the value of the static and don't provide a way to + // get the address of or a reference to the static. + unsafe extern "C" { + #[rustc_objc_class = $classname] + safe static VAL: $crate::os::darwin::objc::Class; + } + VAL +}} + +/// Gets a reference to an Objective-C selector. +/// +/// This macro will yield an expression of type [`SEL`] for the given method name string literal. +/// +/// It is similar to Objective-C’s `@selector` directive. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(darwin_objc)] +/// use core::os::darwin::objc; +/// +/// let alloc_sel = objc::selector!("alloc"); +/// let init_sel = objc::selector!("initWithCString:encoding:"); +/// ``` +#[allow_internal_unstable(rustc_attrs)] +pub macro selector($methname:expr) {{ + // Since static Objective-C selector references actually end up with multiple definitions + // across dylib boundaries, we only expose the value of the static and don't provide a way to + // get the address of or a reference to the static. + unsafe extern "C" { + #[rustc_objc_selector = $methname] + safe static VAL: $crate::os::darwin::objc::SEL; + } + VAL +}} diff --git a/library/core/src/os/mod.rs b/library/core/src/os/mod.rs new file mode 100644 index 00000000000..897f59f530e --- /dev/null +++ b/library/core/src/os/mod.rs @@ -0,0 +1,24 @@ +//! OS-specific functionality. + +#![unstable(feature = "darwin_objc", issue = "145496")] + +#[cfg(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +))] +#[unstable(issue = "none", feature = "std_internals")] +pub mod darwin {} + +// darwin +#[cfg(not(all( + doc, + any( + all(target_arch = "wasm32", not(target_os = "wasi")), + all(target_vendor = "fortanix", target_env = "sgx") + ) +)))] +#[cfg(any(target_vendor = "apple", doc))] +pub mod darwin; diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs index 3892f831076..c57a8d81ade 100644 --- a/library/core/src/tuple.rs +++ b/library/core/src/tuple.rs @@ -1,7 +1,7 @@ // See core/src/primitive_docs.rs for documentation. use crate::cmp::Ordering::{self, *}; -use crate::marker::{ConstParamTy_, StructuralPartialEq, UnsizedConstParamTy}; +use crate::marker::{ConstParamTy_, StructuralPartialEq}; use crate::ops::ControlFlow::{self, Break, Continue}; // Recursive macro for implementing n-ary tuple functions and operations @@ -47,19 +47,13 @@ macro_rules! tuple_impls { maybe_tuple_doc! { $($T)+ @ #[unstable(feature = "adt_const_params", issue = "95174")] + #[unstable_feature_bound(unsized_const_params)] impl<$($T: ConstParamTy_),+> ConstParamTy_ for ($($T,)+) {} } maybe_tuple_doc! { $($T)+ @ - #[unstable(feature = "unsized_const_params", issue = "95174")] - impl<$($T: UnsizedConstParamTy),+> UnsizedConstParamTy for ($($T,)+) - {} - } - - maybe_tuple_doc! { - $($T)+ @ #[unstable(feature = "structural_match", issue = "31434")] impl<$($T),+> StructuralPartialEq for ($($T,)+) {} diff --git a/library/coretests/tests/ascii.rs b/library/coretests/tests/ascii.rs index ce09ee507f1..297aa114e00 100644 --- a/library/coretests/tests/ascii.rs +++ b/library/coretests/tests/ascii.rs @@ -505,3 +505,10 @@ fn test_escape_ascii_iter() { let _ = it.advance_back_by(4); assert_eq!(it.to_string(), r#"fastpath\xffremainder"#); } + +#[test] +fn test_invalid_u8() { + for c in 128..=255 { + assert_eq!(core::ascii::Char::from_u8(c), None); + } +} diff --git a/library/std/src/os/darwin/mod.rs b/library/std/src/os/darwin/mod.rs index 3b1bd974fa3..ff184f477fb 100644 --- a/library/std/src/os/darwin/mod.rs +++ b/library/std/src/os/darwin/mod.rs @@ -17,6 +17,8 @@ #![doc(cfg(target_vendor = "apple"))] pub mod fs; +pub mod objc; + // deprecated, but used for public reexport under `std::os::unix::raw`, as // well as `std::os::macos`/`std::os::ios`, because those modules precede the // decision to remove these. diff --git a/library/std/src/os/darwin/objc.rs b/library/std/src/os/darwin/objc.rs new file mode 100644 index 00000000000..a4b31fee7c5 --- /dev/null +++ b/library/std/src/os/darwin/objc.rs @@ -0,0 +1,13 @@ +//! Defines types and macros for Objective-C interoperability. +//! +//! This module re-exports all the items in [`core::os::darwin::objc`]. +//! +//! [`core::os::darwin::objc`]: ../../../../core/os/darwin/objc/index.html "mod core::os::darwin::objc" + +#![unstable(feature = "darwin_objc", issue = "145496")] + +// We can't generate an intra-doc link for this automatically since `core::os::darwin` isn't +// compiled into `core` on every platform even though it's documented on every platform. +// We just link to it directly in the module documentation above instead. +#[cfg(not(doc))] +pub use core::os::darwin::objc::*; diff --git a/library/std/src/sys/fs/unix.rs b/library/std/src/sys/fs/unix.rs index dfd6ce56a76..33a1e7ff5e4 100644 --- a/library/std/src/sys/fs/unix.rs +++ b/library/std/src/sys/fs/unix.rs @@ -21,29 +21,31 @@ use libc::fstatat as fstatat64; #[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))] use libc::fstatat64; #[cfg(any( + target_os = "aix", target_os = "android", - target_os = "solaris", + target_os = "freebsd", target_os = "fuchsia", - target_os = "redox", target_os = "illumos", - target_os = "aix", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", all(target_os = "linux", target_env = "musl"), ))] use libc::readdir as readdir64; #[cfg(not(any( + target_os = "aix", target_os = "android", - target_os = "linux", - target_os = "solaris", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "hurd", target_os = "illumos", target_os = "l4re", - target_os = "fuchsia", - target_os = "redox", - target_os = "aix", + target_os = "linux", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", - target_os = "hurd", )))] use libc::readdir_r as readdir64_r; #[cfg(any(all(target_os = "linux", not(target_env = "musl")), target_os = "hurd"))] @@ -271,16 +273,17 @@ unsafe impl Send for Dir {} unsafe impl Sync for Dir {} #[cfg(any( + target_os = "aix", target_os = "android", - target_os = "linux", - target_os = "solaris", - target_os = "illumos", + target_os = "freebsd", target_os = "fuchsia", - target_os = "redox", - target_os = "aix", + target_os = "hurd", + target_os = "illumos", + target_os = "linux", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", - target_os = "hurd", ))] pub struct DirEntry { dir: Arc<InnerReadDir>, @@ -295,16 +298,17 @@ pub struct DirEntry { // we're not using the immediate `d_name` on these targets. Keeping this as an // `entry` field in `DirEntry` helps reduce the `cfg` boilerplate elsewhere. #[cfg(any( + target_os = "aix", target_os = "android", - target_os = "linux", - target_os = "solaris", - target_os = "illumos", + target_os = "freebsd", target_os = "fuchsia", - target_os = "redox", - target_os = "aix", + target_os = "hurd", + target_os = "illumos", + target_os = "linux", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", - target_os = "hurd", ))] struct dirent64_min { d_ino: u64, @@ -319,16 +323,17 @@ struct dirent64_min { } #[cfg(not(any( + target_os = "aix", target_os = "android", - target_os = "linux", - target_os = "solaris", - target_os = "illumos", + target_os = "freebsd", target_os = "fuchsia", - target_os = "redox", - target_os = "aix", + target_os = "hurd", + target_os = "illumos", + target_os = "linux", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", - target_os = "hurd", )))] pub struct DirEntry { dir: Arc<InnerReadDir>, @@ -698,16 +703,17 @@ impl Iterator for ReadDir { type Item = io::Result<DirEntry>; #[cfg(any( + target_os = "aix", target_os = "android", - target_os = "linux", - target_os = "solaris", + target_os = "freebsd", target_os = "fuchsia", - target_os = "redox", + target_os = "hurd", target_os = "illumos", - target_os = "aix", + target_os = "linux", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", - target_os = "hurd", ))] fn next(&mut self) -> Option<io::Result<DirEntry>> { use crate::sys::os::{errno, set_errno}; @@ -768,6 +774,9 @@ impl Iterator for ReadDir { // only access those bytes. #[cfg(not(target_os = "vita"))] let entry = dirent64_min { + #[cfg(target_os = "freebsd")] + d_ino: (*entry_ptr).d_fileno, + #[cfg(not(target_os = "freebsd"))] d_ino: (*entry_ptr).d_ino as u64, #[cfg(not(any( target_os = "solaris", @@ -791,16 +800,17 @@ impl Iterator for ReadDir { } #[cfg(not(any( + target_os = "aix", target_os = "android", - target_os = "linux", - target_os = "solaris", + target_os = "freebsd", target_os = "fuchsia", - target_os = "redox", + target_os = "hurd", target_os = "illumos", - target_os = "aix", + target_os = "linux", target_os = "nto", + target_os = "redox", + target_os = "solaris", target_os = "vita", - target_os = "hurd", )))] fn next(&mut self) -> Option<io::Result<DirEntry>> { if self.end_of_stream { @@ -970,36 +980,32 @@ impl DirEntry { } #[cfg(any( - target_os = "linux", + target_os = "aix", + target_os = "android", target_os = "cygwin", target_os = "emscripten", - target_os = "android", - target_os = "solaris", - target_os = "illumos", - target_os = "haiku", - target_os = "l4re", - target_os = "fuchsia", - target_os = "redox", - target_os = "vxworks", target_os = "espidf", + target_os = "freebsd", + target_os = "fuchsia", + target_os = "haiku", target_os = "horizon", - target_os = "vita", - target_os = "aix", - target_os = "nto", target_os = "hurd", + target_os = "illumos", + target_os = "l4re", + target_os = "linux", + target_os = "nto", + target_os = "redox", target_os = "rtems", + target_os = "solaris", + target_os = "vita", + target_os = "vxworks", target_vendor = "apple", ))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 } - #[cfg(any( - target_os = "freebsd", - target_os = "openbsd", - target_os = "netbsd", - target_os = "dragonfly" - ))] + #[cfg(any(target_os = "openbsd", target_os = "netbsd", target_os = "dragonfly"))] pub fn ino(&self) -> u64 { self.entry.d_fileno as u64 } @@ -1014,7 +1020,6 @@ impl DirEntry { #[cfg(any( target_os = "netbsd", target_os = "openbsd", - target_os = "freebsd", target_os = "dragonfly", target_vendor = "apple", ))] @@ -1030,7 +1035,6 @@ impl DirEntry { #[cfg(not(any( target_os = "netbsd", target_os = "openbsd", - target_os = "freebsd", target_os = "dragonfly", target_vendor = "apple", )))] @@ -1040,6 +1044,7 @@ impl DirEntry { #[cfg(not(any( target_os = "android", + target_os = "freebsd", target_os = "linux", target_os = "solaris", target_os = "illumos", @@ -1055,6 +1060,7 @@ impl DirEntry { } #[cfg(any( target_os = "android", + target_os = "freebsd", target_os = "linux", target_os = "solaris", target_os = "illumos", diff --git a/library/test/src/cli.rs b/library/test/src/cli.rs index 1b3f9e2564c..35291cc15c9 100644 --- a/library/test/src/cli.rs +++ b/library/test/src/cli.rs @@ -57,6 +57,7 @@ fn optgroups() -> getopts::Options { .optflag("", "test", "Run tests and not benchmarks") .optflag("", "bench", "Run benchmarks instead of tests") .optflag("", "list", "List all tests and benchmarks") + .optflag("", "fail-fast", "Don't start new tests after the first failure") .optflag("h", "help", "Display this message") .optopt("", "logfile", "Write logs to the specified file (deprecated)", "PATH") .optflag( @@ -260,6 +261,7 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes { // Unstable flags let force_run_in_process = unstable_optflag!(matches, allow_unstable, "force-run-in-process"); let exclude_should_panic = unstable_optflag!(matches, allow_unstable, "exclude-should-panic"); + let fail_fast = unstable_optflag!(matches, allow_unstable, "fail-fast"); let time_options = get_time_options(&matches, allow_unstable)?; let shuffle = get_shuffle(&matches, allow_unstable)?; let shuffle_seed = get_shuffle_seed(&matches, allow_unstable)?; @@ -306,7 +308,7 @@ fn parse_opts_impl(matches: getopts::Matches) -> OptRes { skip, time_options, options, - fail_fast: false, + fail_fast, }; Ok(test_opts) diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 2965174b45b..12e09cb07db 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -63,6 +63,21 @@ build/ debug/ release/ + # Build directory for various tools like `typos` that are only ever + # built for the host system, and always with stage0 cargo. + misc-tools/ + bin/ + target/ + + # Directory where js dependencies like tsc and eslint are stored. + node_modules/ + .bin/ + + # Copy of package.json and package-lock.json, because npm requires these + # to be in the same directory as `node_modules`. + package.json + package-lock.json + # Output of the dist-related steps like dist-std, dist-rustc, and dist-docs dist/ diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index 2ece53eb0cc..19e87f9c293 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -1039,6 +1039,9 @@ class RustBuild(object): # See also: <https://github.com/rust-lang/rust/issues/70208>. if "CARGO_BUILD_TARGET" in env: del env["CARGO_BUILD_TARGET"] + # if in CI, don't use incremental build when building bootstrap. + if "GITHUB_ACTIONS" in env: + env["CARGO_INCREMENTAL"] = "0" env["CARGO_TARGET_DIR"] = build_dir env["RUSTC"] = self.rustc() env["LD_LIBRARY_PATH"] = ( @@ -1145,7 +1148,8 @@ class RustBuild(object): os.path.join(self.rust_root, "src/bootstrap/Cargo.toml"), "-Zroot-dir=" + self.rust_root, ] - args.extend("--verbose" for _ in range(self.verbose)) + # verbose cargo output is very noisy, so only enable it with -vv + args.extend("--verbose" for _ in range(self.verbose - 1)) if "BOOTSTRAP_TRACING" in env: args.append("--features=tracing") diff --git a/src/bootstrap/configure.py b/src/bootstrap/configure.py index b05a5cc8b81..1915986be28 100755 --- a/src/bootstrap/configure.py +++ b/src/bootstrap/configure.py @@ -340,6 +340,11 @@ o( "don't truncate options when printing them in this configure script", ) v("set", None, "set arbitrary key/value pairs in TOML configuration") +v( + "parallel-frontend-threads", + "rust.parallel-frontend-threads", + "number of parallel threads for rustc compilation", +) def p(msg): diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index 83ed7430c39..d43d261ad6c 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -619,11 +619,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) { let version = get_llvm_version(builder, llvm_config); let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok()); if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) - && major >= 19 + && major >= 20 { return; } - panic!("\n\nbad LLVM version: {version}, need >=19\n\n") + panic!("\n\nbad LLVM version: {version}, need >=20\n\n") } fn configure_cmake( diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs index 723ba80eaf8..e7f5879b5f5 100644 --- a/src/bootstrap/src/core/build_steps/test.rs +++ b/src/bootstrap/src/core/build_steps/test.rs @@ -3418,9 +3418,6 @@ impl Step for TierCheck { ); cargo.arg(builder.src.join("src/doc/rustc/src/platform-support.md")); cargo.arg(builder.rustc(self.test_compiler)); - if builder.is_verbose() { - cargo.arg("--verbose"); - } let _guard = builder.msg_test( "platform support check", diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs index dcc4898cae1..4f096d50ea5 100644 --- a/src/bootstrap/src/core/build_steps/tool.rs +++ b/src/bootstrap/src/core/build_steps/tool.rs @@ -394,6 +394,9 @@ macro_rules! bootstrap_tool { } impl<'a> Builder<'a> { + /// Ensure a tool is built, then get the path to its executable. + /// + /// The actual building, if any, will be handled via [`ToolBuild`]. pub fn tool_exe(&self, tool: Tool) -> PathBuf { match tool { $(Tool::$name => @@ -1552,6 +1555,8 @@ pub const TEST_FLOAT_PARSE_ALLOW_FEATURES: &str = "f16,cfg_target_has_reliable_f impl Builder<'_> { /// Gets a `BootstrapCommand` which is ready to run `tool` in `stage` built for /// `host`. + /// + /// This also ensures that the given tool is built (using [`ToolBuild`]). pub fn tool_cmd(&self, tool: Tool) -> BootstrapCommand { let mut cmd = command(self.tool_exe(tool)); let compiler = self.compiler(0, self.config.host_target); diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs index 924bb4adb42..6121bf7d9cd 100644 --- a/src/bootstrap/src/core/builder/cargo.rs +++ b/src/bootstrap/src/core/builder/cargo.rs @@ -679,6 +679,12 @@ impl Builder<'_> { // cargo would implicitly add it, it was discover that sometimes bootstrap only use // `rustflags` without `cargo` making it required. rustflags.arg("-Zunstable-options"); + + // Add parallel frontend threads configuration + if let Some(threads) = self.config.rust_parallel_frontend_threads { + rustflags.arg(&format!("-Zthreads={threads}")); + } + for (restricted_mode, name, values) in EXTRA_CHECK_CFGS { if restricted_mode.is_none() || *restricted_mode == Some(mode) { rustflags.arg(&check_cfg_arg(name, *values)); @@ -1133,7 +1139,7 @@ impl Builder<'_> { cargo.env("RUSTC_BACKTRACE_ON_ICE", "1"); } - if self.is_verbose() { + if self.is_verbose_than(1) { // This provides very useful logs especially when debugging build cache-related stuff. cargo.env("CARGO_LOG", "cargo::core::compiler::fingerprint=info"); } @@ -1275,8 +1281,9 @@ impl Builder<'_> { cargo.env("WINAPI_NO_BUNDLED_LIBRARIES", "1"); } - for _ in 0..self.verbosity { - cargo.arg("-v"); + // verbose cargo output is very noisy, so only enable it with -vv + for _ in 0..self.verbosity.saturating_sub(1) { + cargo.arg("--verbose"); } match (mode, self.config.rust_codegen_units_std, self.config.rust_codegen_units) { diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs index 678a9b63952..efb7ad91699 100644 --- a/src/bootstrap/src/core/config/config.rs +++ b/src/bootstrap/src/core/config/config.rs @@ -191,7 +191,6 @@ pub struct Config { pub rust_optimize: RustOptimize, pub rust_codegen_units: Option<u32>, pub rust_codegen_units_std: Option<u32>, - pub rustc_debug_assertions: bool, pub std_debug_assertions: bool, pub tools_debug_assertions: bool, @@ -222,6 +221,8 @@ pub struct Config { pub rust_validate_mir_opts: Option<u32>, pub rust_std_features: BTreeSet<String>, pub rust_break_on_ice: bool, + pub rust_parallel_frontend_threads: Option<u32>, + pub llvm_profile_use: Option<String>, pub llvm_profile_generate: bool, pub llvm_libunwind_default: Option<LlvmLibunwind>, @@ -534,6 +535,7 @@ impl Config { backtrace_on_ice: rust_backtrace_on_ice, verify_llvm_ir: rust_verify_llvm_ir, thin_lto_import_instr_limit: rust_thin_lto_import_instr_limit, + parallel_frontend_threads: rust_parallel_frontend_threads, remap_debuginfo: rust_remap_debuginfo, jemalloc: rust_jemalloc, test_compare_mode: rust_test_compare_mode, @@ -1298,6 +1300,7 @@ impl Config { rust_overflow_checks_std: rust_overflow_checks_std .or(rust_overflow_checks) .unwrap_or(rust_debug == Some(true)), + rust_parallel_frontend_threads: rust_parallel_frontend_threads.map(threads_from_config), rust_profile_generate: flags_rust_profile_generate.or(rust_profile_generate), rust_profile_use: flags_rust_profile_use.or(rust_profile_use), rust_randomize_layout: rust_randomize_layout.unwrap_or(false), @@ -1853,13 +1856,7 @@ fn load_toml_config( } else { toml_path.clone() }); - ( - get_toml(&toml_path).unwrap_or_else(|e| { - eprintln!("ERROR: Failed to parse '{}': {e}", toml_path.display()); - exit!(2); - }), - path, - ) + (get_toml(&toml_path).unwrap_or_else(|e| bad_config(&toml_path, e)), path) } else { (TomlConfig::default(), None) } @@ -1892,10 +1889,8 @@ fn postprocess_toml( .unwrap() .join(include_path); - let included_toml = get_toml(&include_path).unwrap_or_else(|e| { - eprintln!("ERROR: Failed to parse '{}': {e}", include_path.display()); - exit!(2); - }); + let included_toml = + get_toml(&include_path).unwrap_or_else(|e| bad_config(&include_path, e)); toml.merge( Some(include_path), &mut Default::default(), @@ -2398,3 +2393,98 @@ pub(crate) fn read_file_by_commit<'a>( git.arg("show").arg(format!("{commit}:{}", file.to_str().unwrap())); git.run_capture_stdout(dwn_ctx.exec_ctx).stdout() } + +fn bad_config(toml_path: &Path, e: toml::de::Error) -> ! { + eprintln!("ERROR: Failed to parse '{}': {e}", toml_path.display()); + let e_s = e.to_string(); + if e_s.contains("unknown field") + && let Some(field_name) = e_s.split("`").nth(1) + && let sections = find_correct_section_for_field(field_name) + && !sections.is_empty() + { + if sections.len() == 1 { + match sections[0] { + WouldBeValidFor::TopLevel { is_section } => { + if is_section { + eprintln!( + "hint: section name `{field_name}` used as a key within a section" + ); + } else { + eprintln!("hint: try using `{field_name}` as a top level key"); + } + } + WouldBeValidFor::Section(section) => { + eprintln!("hint: try moving `{field_name}` to the `{section}` section") + } + } + } else { + eprintln!( + "hint: `{field_name}` would be valid {}", + join_oxford_comma(sections.iter(), "or"), + ); + } + } + + exit!(2); +} + +#[derive(Copy, Clone, Debug)] +enum WouldBeValidFor { + TopLevel { is_section: bool }, + Section(&'static str), +} + +fn join_oxford_comma( + mut parts: impl ExactSizeIterator<Item = impl std::fmt::Display>, + conj: &str, +) -> String { + use std::fmt::Write; + let mut out = String::new(); + + assert!(parts.len() > 1); + while let Some(part) = parts.next() { + if parts.len() == 0 { + write!(&mut out, "{conj} {part}") + } else { + write!(&mut out, "{part}, ") + } + .unwrap(); + } + out +} + +impl std::fmt::Display for WouldBeValidFor { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::TopLevel { .. } => write!(f, "at top level"), + Self::Section(section_name) => write!(f, "in section `{section_name}`"), + } + } +} + +fn find_correct_section_for_field(field_name: &str) -> Vec<WouldBeValidFor> { + let sections = ["build", "install", "llvm", "gcc", "rust", "dist"]; + sections + .iter() + .map(Some) + .chain([None]) + .filter_map(|section_name| { + let dummy_config_str = if let Some(section_name) = section_name { + format!("{section_name}.{field_name} = 0\n") + } else { + format!("{field_name} = 0\n") + }; + let is_unknown_field = toml::from_str::<toml::Value>(&dummy_config_str) + .and_then(TomlConfig::deserialize) + .err() + .is_some_and(|e| e.to_string().contains("unknown field")); + if is_unknown_field { + None + } else { + Some(section_name.copied().map(WouldBeValidFor::Section).unwrap_or_else(|| { + WouldBeValidFor::TopLevel { is_section: sections.contains(&field_name) } + })) + } + }) + .collect() +} diff --git a/src/bootstrap/src/core/config/toml/rust.rs b/src/bootstrap/src/core/config/toml/rust.rs index 4832a1d37b7..e5987d7040a 100644 --- a/src/bootstrap/src/core/config/toml/rust.rs +++ b/src/bootstrap/src/core/config/toml/rust.rs @@ -66,6 +66,7 @@ define_config! { validate_mir_opts: Option<u32> = "validate-mir-opts", std_features: Option<BTreeSet<String>> = "std-features", break_on_ice: Option<bool> = "break-on-ice", + parallel_frontend_threads: Option<u32> = "parallel-frontend-threads", } } @@ -357,6 +358,7 @@ pub fn check_incompatible_options_for_ci_rustc( validate_mir_opts: _, frame_pointers: _, break_on_ice: _, + parallel_frontend_threads: _, } = ci_rust_config; // There are two kinds of checks for CI rustc incompatible options: diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs index 03b39882e30..2c48cebd2df 100644 --- a/src/bootstrap/src/utils/change_tracker.rs +++ b/src/bootstrap/src/utils/change_tracker.rs @@ -546,4 +546,9 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[ severity: ChangeSeverity::Info, summary: "The default value of the `gcc.download-ci-gcc` option has been changed to `true`.", }, + ChangeInfo { + change_id: 146458, + severity: ChangeSeverity::Info, + summary: "There is now a bootstrap option called `rust.parallel-frontend-threads`, which can be used to set the number of threads for the compiler frontend used during compilation of Rust code.", + }, ]; diff --git a/src/ci/docker/README.md b/src/ci/docker/README.md index 488a6a2bce1..4ee02e9bf00 100644 --- a/src/ci/docker/README.md +++ b/src/ci/docker/README.md @@ -14,9 +14,9 @@ To run a specific CI job locally, you can use the `citool` Rust crate: cargo run --manifest-path src/ci/citool/Cargo.toml run-local <job-name> ``` -For example, to run the `x86_64-gnu-llvm-19-1` job: +For example, to run the `x86_64-gnu-llvm-20-1` job: ``` -cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-llvm-19-1 +cargo run --manifest-path src/ci/citool/Cargo.toml run-local x86_64-gnu-llvm-20-1 ``` The job will output artifacts in an `obj/<image-name>` dir at the root of a repository. Note @@ -27,10 +27,10 @@ Docker image executed in the given CI job. while locally, to the `obj/<image-name>` directory. This is primarily to prevent strange linker errors when using multiple Docker images. -For some Linux workflows (for example `x86_64-gnu-llvm-19-N`), the process is more involved. You will need to see which script is executed for the given workflow inside the [`jobs.yml`](../github-actions/jobs.yml) file and pass it through the `DOCKER_SCRIPT` environment variable. For example, to reproduce the `x86_64-gnu-llvm-19-3` workflow, you can run the following script: +For some Linux workflows (for example `x86_64-gnu-llvm-20-N`), the process is more involved. You will need to see which script is executed for the given workflow inside the [`jobs.yml`](../github-actions/jobs.yml) file and pass it through the `DOCKER_SCRIPT` environment variable. For example, to reproduce the `x86_64-gnu-llvm-20-3` workflow, you can run the following script: ``` -DOCKER_SCRIPT=x86_64-gnu-llvm3.sh ./src/ci/docker/run.sh x86_64-gnu-llvm-19 +DOCKER_SCRIPT=x86_64-gnu-llvm3.sh ./src/ci/docker/run.sh x86_64-gnu-llvm-20 ``` ## Local Development diff --git a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile index e73fbe506f7..adbb1f03378 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu-llvm-19/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu-llvm-20/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:24.10 +FROM ubuntu:25.04 ARG DEBIAN_FRONTEND=noninteractive @@ -15,8 +15,8 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ cmake \ sudo \ gdb \ - llvm-19-tools \ - llvm-19-dev \ + llvm-20-tools \ + llvm-20-dev \ libedit-dev \ libssl-dev \ pkg-config \ @@ -43,7 +43,7 @@ ENV EXTERNAL_LLVM 1 # Using llvm-link-shared due to libffi issues -- see #34486 ENV RUST_CONFIGURE_ARGS \ --build=aarch64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-19 \ + --llvm-root=/usr/lib/llvm-20 \ --enable-llvm-link-shared \ --set rust.randomize-layout=true \ --set rust.thin-lto-import-instr-limit=10 diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile deleted file mode 100644 index 5cba7c564f1..00000000000 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-19/Dockerfile +++ /dev/null @@ -1,66 +0,0 @@ -FROM ubuntu:24.10 - -ARG DEBIAN_FRONTEND=noninteractive - -RUN apt-get update && apt-get install -y --no-install-recommends \ - bzip2 \ - g++ \ - gcc-multilib \ - make \ - ninja-build \ - file \ - curl \ - ca-certificates \ - python3 \ - git \ - cmake \ - sudo \ - gdb \ - llvm-19-tools \ - llvm-19-dev \ - libedit-dev \ - libssl-dev \ - pkg-config \ - zlib1g-dev \ - xz-utils \ - nodejs \ - mingw-w64 \ - # libgccjit dependencies - flex \ - libmpfr-dev \ - libgmp-dev \ - libmpc3 \ - libmpc-dev \ - && rm -rf /var/lib/apt/lists/* - -# Install powershell (universal package) so we can test x.ps1 on Linux -# FIXME: need a "universal" version that supports libicu74, but for now it still works to ignore that dep. -RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \ - dpkg --ignore-depends=libicu72 -i powershell.deb && \ - rm -f powershell.deb - -COPY scripts/sccache.sh /scripts/ -RUN sh /scripts/sccache.sh - -# We are disabling CI LLVM since this builder is intentionally using a host -# LLVM, rather than the typical src/llvm-project LLVM. -ENV NO_DOWNLOAD_CI_LLVM 1 -ENV EXTERNAL_LLVM 1 - -# Using llvm-link-shared due to libffi issues -- see #34486 -ENV RUST_CONFIGURE_ARGS \ - --build=x86_64-unknown-linux-gnu \ - --llvm-root=/usr/lib/llvm-19 \ - --enable-llvm-link-shared \ - --set rust.randomize-layout=true \ - --set rust.thin-lto-import-instr-limit=10 - -COPY scripts/shared.sh /scripts/ - -COPY scripts/x86_64-gnu-llvm.sh /scripts/ -COPY scripts/x86_64-gnu-llvm2.sh /scripts/ -COPY scripts/x86_64-gnu-llvm3.sh /scripts/ -COPY scripts/stage_2_test_set1.sh /scripts/ -COPY scripts/stage_2_test_set2.sh /scripts/ - -ENV SCRIPT "Must specify DOCKER_SCRIPT for this image" diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml index 35b9456d37d..b3e3fe7d96a 100644 --- a/src/ci/github-actions/jobs.yml +++ b/src/ci/github-actions/jobs.yml @@ -122,19 +122,19 @@ pr: # tidy. This speeds up the PR CI job by ~1 minute. SKIP_SUBMODULES: src/gcc <<: *job-linux-4c - - name: x86_64-gnu-llvm-19 + - name: x86_64-gnu-llvm-20 env: ENABLE_GCC_CODEGEN: "1" DOCKER_SCRIPT: x86_64-gnu-llvm.sh <<: *job-linux-4c - - name: aarch64-gnu-llvm-19-1 + - name: aarch64-gnu-llvm-20-1 env: - IMAGE: aarch64-gnu-llvm-19 + IMAGE: aarch64-gnu-llvm-20 DOCKER_SCRIPT: stage_2_test_set1.sh <<: *job-aarch64-linux - - name: aarch64-gnu-llvm-19-2 + - name: aarch64-gnu-llvm-20-2 env: - IMAGE: aarch64-gnu-llvm-19 + IMAGE: aarch64-gnu-llvm-20 DOCKER_SCRIPT: stage_2_test_set2.sh <<: *job-aarch64-linux - name: x86_64-gnu-tools @@ -397,31 +397,6 @@ auto: DOCKER_SCRIPT: x86_64-gnu-llvm3.sh <<: *job-linux-4c - # The x86_64-gnu-llvm-19 job is split into multiple jobs to run tests in parallel. - # x86_64-gnu-llvm-19-1 skips tests that run in x86_64-gnu-llvm-19-{2,3}. - - name: x86_64-gnu-llvm-19-1 - env: - RUST_BACKTRACE: 1 - IMAGE: x86_64-gnu-llvm-19 - DOCKER_SCRIPT: stage_2_test_set2.sh - <<: *job-linux-4c - - # Skip tests that run in x86_64-gnu-llvm-19-{1,3} - - name: x86_64-gnu-llvm-19-2 - env: - RUST_BACKTRACE: 1 - IMAGE: x86_64-gnu-llvm-19 - DOCKER_SCRIPT: x86_64-gnu-llvm2.sh - <<: *job-linux-4c - - # Skip tests that run in x86_64-gnu-llvm-19-{1,2} - - name: x86_64-gnu-llvm-19-3 - env: - RUST_BACKTRACE: 1 - IMAGE: x86_64-gnu-llvm-19 - DOCKER_SCRIPT: x86_64-gnu-llvm3.sh - <<: *job-linux-4c - - name: x86_64-gnu-nopt <<: *job-linux-4c diff --git a/src/doc/rustc-dev-guide/src/tests/intro.md b/src/doc/rustc-dev-guide/src/tests/intro.md index b90c16d602c..4fa63b83b17 100644 --- a/src/doc/rustc-dev-guide/src/tests/intro.md +++ b/src/doc/rustc-dev-guide/src/tests/intro.md @@ -70,10 +70,12 @@ package tests: Tidy is a custom tool used for validating source code style and formatting conventions, such as rejecting long lines. There is more information in the -[section on coding conventions](../conventions.md#formatting). +[section on coding conventions](../conventions.md#formatting) or the [Tidy Readme]. > Examples: `./x test tidy` +[Tidy Readme]: https://github.com/rust-lang/rust/blob/master/src/tools/tidy/Readme.md + ### Formatting diff --git a/src/doc/rustc/src/target-tier-policy.md b/src/doc/rustc/src/target-tier-policy.md index 28d3dc32a63..f6b78eed24f 100644 --- a/src/doc/rustc/src/target-tier-policy.md +++ b/src/doc/rustc/src/target-tier-policy.md @@ -701,4 +701,4 @@ RFC process, with approval by the compiler and infra teams. Any such proposal will be communicated widely to the Rust community, both when initially proposed and before being dropped from a stable release. -[MCP]: https://forge.rust-lang.org/compiler/mcp.html +[MCP]: https://forge.rust-lang.org/compiler/proposals-and-stabilization.html#how-do-i-submit-an-mcp diff --git a/src/doc/rustc/src/tests/index.md b/src/doc/rustc/src/tests/index.md index 7609ed23351..7a108a71beb 100644 --- a/src/doc/rustc/src/tests/index.md +++ b/src/doc/rustc/src/tests/index.md @@ -158,6 +158,18 @@ unstable-options` flag. See [tracking issue The following options affect how tests are executed. +#### `--fail-fast` + +Stops tests after the first failure. + +If running tests in parallel (which is the default), then tests that have already been started on +other threads will be allowed to run to completion before the process exits. + +Note that when running tests in parallel, the test execution order is non-deterministic: +if multiple tests would fail, the first failure encountered will be reported. + +⚠️ 🚧 This requires the `-Z unstable-options` flag. + #### `--test-threads` _NUM_THREADS_ Sets the number of threads to use for running tests in parallel. By default, diff --git a/src/tools/cargo b/src/tools/cargo -Subproject 24bb93c388fb8c211a37986539f24a819dc669d +Subproject 966f94733bbc94ca51ff9f1e4c49ad250ebbdc5 diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs index 68f0b5ea255..40fd2cdeb86 100644 --- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs +++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs @@ -126,7 +126,7 @@ fn check_rvalue<'tcx>( ) -> McfResult { match rvalue { Rvalue::ThreadLocalRef(_) => Err((span, "cannot access thread local storage in const fn".into())), - Rvalue::Len(place) | Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => { + Rvalue::Discriminant(place) | Rvalue::Ref(_, _, place) | Rvalue::RawPtr(_, place) => { check_place(cx, *place, span, body, msrv) }, Rvalue::CopyForDeref(place) => check_place(cx, *place, span, body, msrv), diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 143ccdcb9e5..6da102b1b5f 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -203,6 +203,10 @@ impl CodegenBackend { Self::Llvm => "llvm", } } + + pub fn is_llvm(self) -> bool { + matches!(self, Self::Llvm) + } } /// Configuration for `compiletest` *per invocation*. diff --git a/src/tools/compiletest/src/directives/needs.rs b/src/tools/compiletest/src/directives/needs.rs index ee46f4c70cb..3b7a9478717 100644 --- a/src/tools/compiletest/src/directives/needs.rs +++ b/src/tools/compiletest/src/directives/needs.rs @@ -81,8 +81,8 @@ pub(super) fn handle_needs( }, Need { name: "needs-enzyme", - condition: config.has_enzyme, - ignore_reason: "ignored when LLVM Enzyme is disabled", + condition: config.has_enzyme && config.default_codegen_backend.is_llvm(), + ignore_reason: "ignored when LLVM Enzyme is disabled or LLVM is not the default codegen backend", }, Need { name: "needs-run-enabled", @@ -161,8 +161,8 @@ pub(super) fn handle_needs( }, Need { name: "needs-llvm-zstd", - condition: cache.llvm_zstd, - ignore_reason: "ignored if LLVM wasn't build with zstd for ELF section compression", + condition: cache.llvm_zstd && config.default_codegen_backend.is_llvm(), + ignore_reason: "ignored if LLVM wasn't build with zstd for ELF section compression or LLVM is not the default codegen backend", }, Need { name: "needs-rustc-debug-assertions", @@ -279,7 +279,10 @@ pub(super) fn handle_needs( // Handled elsewhere. if name == "needs-llvm-components" { - return IgnoreDecision::Continue; + if config.default_codegen_backend.is_llvm() { + return IgnoreDecision::Continue; + } + return IgnoreDecision::Ignore { reason: "LLVM specific test".into() }; } let mut found_valid = false; diff --git a/src/tools/compiletest/src/executor.rs b/src/tools/compiletest/src/executor.rs index 37cc17351d5..c8e13d44573 100644 --- a/src/tools/compiletest/src/executor.rs +++ b/src/tools/compiletest/src/executor.rs @@ -295,11 +295,14 @@ fn filter_tests(opts: &Config, tests: Vec<CollectedTest>) -> Vec<CollectedTest> let mut filtered = tests; let matches_filter = |test: &CollectedTest, filter_str: &str| { - let filterable_path = test.desc.filterable_path.as_str(); if opts.filter_exact { - filterable_path == filter_str + // When `--exact` is used we must use `filterable_path` to get + // reasonable filtering behavior. + test.desc.filterable_path.as_str() == filter_str } else { - filterable_path.contains(filter_str) + // For compatibility we use the name (which includes the full path) + // if `--exact` is not used. + test.desc.name.contains(filter_str) } }; diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs index 5e349a20ed2..ce2a3d4b5fb 100644 --- a/src/tools/compiletest/src/lib.rs +++ b/src/tools/compiletest/src/lib.rs @@ -484,7 +484,7 @@ pub fn parse_config(args: Vec<String>) -> Config { let value = matches .opt_str("new-output-capture") .or_else(|| env::var("COMPILETEST_NEW_OUTPUT_CAPTURE").ok()) - .unwrap_or_else(|| "off".to_owned()); + .unwrap_or_else(|| "on".to_owned()); parse_bool_option(&value) .unwrap_or_else(|| panic!("unknown `--new-output-capture` value `{value}` given")) }, diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs index dd7dae9cecf..d907c5de797 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-1.rs @@ -1,4 +1,6 @@ //@revisions: stack tree +// Ensure this even hits the aliasing model +//@compile-flags: -Zmiri-disable-validation //@[tree]compile-flags: -Zmiri-tree-borrows //@error-in-other-file: pointer not dereferenceable diff --git a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.rs b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.rs index 5c947e64142..b54f27bb8b2 100644 --- a/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.rs +++ b/src/tools/miri/tests/fail/both_borrows/issue-miri-1050-2.rs @@ -1,4 +1,6 @@ //@revisions: stack tree +// Ensure this even hits the aliasing model +//@compile-flags: -Zmiri-disable-validation //@[tree]compile-flags: -Zmiri-tree-borrows //@error-in-other-file: is a dangling pointer use std::ptr::NonNull; diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr index d52143500c4..7c4fe748701 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.stack.stderr @@ -11,7 +11,7 @@ help: <TAG> was created by a SharedReadOnly retag at offsets [0x4..0x8] | LL | let ret = unsafe { &(*xraw).1 }; | ^^^^^^^^^^ -help: <TAG> was later invalidated at offsets [0x0..0x8] by a write access +help: <TAG> was later invalidated at offsets [0x4..0x8] by a write access --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr index ee0f313d980..a8e3553aae2 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr.tree.stderr @@ -12,7 +12,7 @@ help: the accessed tag <TAG> was created here, in the initial state Frozen | LL | let ret = unsafe { &(*xraw).1 }; | ^^^^^^^^^^ -help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x8] +help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x4..0x8] --> tests/fail/both_borrows/return_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr index d66c8eeb1af..8411437ea4c 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.stack.stderr @@ -14,7 +14,7 @@ help: <TAG> was created by a SharedReadOnly retag at offsets [0x4..0x8] | LL | let ret = Some(unsafe { &(*xraw).1 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: <TAG> was later invalidated at offsets [0x0..0x8] by a write access +help: <TAG> was later invalidated at offsets [0x4..0x8] by a write access --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr index 16110e5b062..39da45ad6db 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_option.tree.stderr @@ -12,7 +12,7 @@ help: the accessed tag <TAG> was created here, in the initial state Frozen | LL | let ret = Some(unsafe { &(*xraw).1 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x8] +help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x4..0x8] --> tests/fail/both_borrows/return_invalid_shr_option.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr index 727b52ec729..a7c422aa73f 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.stack.stderr @@ -14,7 +14,7 @@ help: <TAG> was created by a SharedReadOnly retag at offsets [0x4..0x8] | LL | let ret = (unsafe { &(*xraw).1 },); | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: <TAG> was later invalidated at offsets [0x0..0x8] by a write access +help: <TAG> was later invalidated at offsets [0x4..0x8] by a write access --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze diff --git a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr index f93698f570e..66b03e57905 100644 --- a/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr +++ b/src/tools/miri/tests/fail/both_borrows/return_invalid_shr_tuple.tree.stderr @@ -12,7 +12,7 @@ help: the accessed tag <TAG> was created here, in the initial state Frozen | LL | let ret = (unsafe { &(*xraw).1 },); | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x0..0x8] +help: the accessed tag <TAG> later transitioned to Disabled due to a foreign write access at offsets [0x4..0x8] --> tests/fail/both_borrows/return_invalid_shr_tuple.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze diff --git a/src/tools/miri/tests/fail/overlapping_assignment_aggregate.rs b/src/tools/miri/tests/fail/overlapping_assignment_aggregate.rs new file mode 100644 index 00000000000..8d7b1946242 --- /dev/null +++ b/src/tools/miri/tests/fail/overlapping_assignment_aggregate.rs @@ -0,0 +1,18 @@ +//! This is like `pass/overlapping_assignment_aggregate_scalar.rs` but with a non-scalar +//! type, and that makes it definite UB. +#![feature(custom_mir, core_intrinsics)] +#![allow(internal_features)] + +use std::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime")] +fn main() { + mir! { + let _1: ([u8; 1],); + { + _1.0 = [0_u8; 1]; + _1 = (_1.0, ); //~ERROR: overlapping ranges + Return() + } + } +} diff --git a/src/tools/miri/tests/fail/overlapping_assignment_aggregate.stderr b/src/tools/miri/tests/fail/overlapping_assignment_aggregate.stderr new file mode 100644 index 00000000000..f2a6d326b71 --- /dev/null +++ b/src/tools/miri/tests/fail/overlapping_assignment_aggregate.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `copy_nonoverlapping` called on overlapping ranges + --> tests/fail/overlapping_assignment_aggregate.rs:LL:CC + | +LL | _1 = (_1.0, ); + | ^^^^^^^^^^^^^ Undefined Behavior occurred here + | + = 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 + = note: BACKTRACE: + = note: inside `main` at tests/fail/overlapping_assignment_aggregate.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 1 previous error + diff --git a/src/tools/miri/tests/fail/validity/nonzero.stderr b/src/tools/miri/tests/fail/validity/nonzero.stderr index 0c3a35d6b9f..7be3ef46639 100644 --- a/src/tools/miri/tests/fail/validity/nonzero.stderr +++ b/src/tools/miri/tests/fail/validity/nonzero.stderr @@ -2,7 +2,7 @@ error: Undefined Behavior: constructing invalid value: encountered 0, but expect --> tests/fail/validity/nonzero.rs:LL:CC | LL | let _x = Some(unsafe { NonZero(0) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Undefined Behavior occurred here + | ^^^^^^^^^^ Undefined Behavior occurred here | = 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/pass/overlapping_assignment_aggregate_scalar.rs b/src/tools/miri/tests/pass/overlapping_assignment_aggregate_scalar.rs new file mode 100644 index 00000000000..0cb2f764242 --- /dev/null +++ b/src/tools/miri/tests/pass/overlapping_assignment_aggregate_scalar.rs @@ -0,0 +1,19 @@ +#![feature(custom_mir, core_intrinsics)] +#![allow(internal_features)] + +use std::intrinsics::mir::*; + +#[custom_mir(dialect = "runtime")] +fn main() { + mir! { + let _1: (u8,); + { + _1.0 = 0_u8; + // This is a scalar type, so overlap is (for now) not UB. + // However, we used to treat such overlapping assignments incorrectly + // (see <https://github.com/rust-lang/rust/issues/146383#issuecomment-3273224645>). + _1 = (_1.0, ); + Return() + } + } +} diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs index 4f9352d11b1..b3e95e087e3 100644 --- a/src/tools/opt-dist/src/training.rs +++ b/src/tools/opt-dist/src/training.rs @@ -39,7 +39,6 @@ fn init_compiler_benchmarks( "--exact-match", crates.join(",").as_str(), ]) - .env("RUST_LOG", "collector=debug") .env("RUSTC", env.rustc_stage_0().as_str()) .env("RUSTC_BOOTSTRAP", "1") .workdir(&env.rustc_perf_dir()); diff --git a/src/tools/tidy/Readme.md b/src/tools/tidy/Readme.md new file mode 100644 index 00000000000..fc9dc6350e9 --- /dev/null +++ b/src/tools/tidy/Readme.md @@ -0,0 +1,112 @@ +# Tidy +Tidy is the Rust project's custom internal linter and a crucial part of our testing and continuous integration (CI) infrastructure. It is designed to enforce a consistent style and formatting across the entire codebase, but its role extends beyond simple linting. Tidy also helps with infrastructure, policy, and documentation, ensuring the project remains organized, functional, and... tidy. + +This document will cover how to use tidy, the specific checks tidy performs, and using tidy directives to manage its behavior. By understanding and utilizing tidy, you can help us maintain the high standards of the Rust project. +## Tidy Checks +### Style and Code Quality +These lints focus on enforcing consistent formatting, style, and general code health. +* [`alphabetical`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/alphabetical/index.html): Checks that lists are sorted alphabetically +* [`style`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/style/index.html): Check to enforce various stylistic guidelines on the Rust codebase. +* [`filenames`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/filenames/index.html): Check to prevent invalid characters in file names. +* [`pal`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/pal/index.html): Check to enforce rules about platform-specific code in std. +* [`target_policy`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/target_policy/index.html): Check for target tier policy compliance. +* [`error_codes`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/error_codes/index.html): Check to ensure error codes are properly documented and tested. + +### Infrastructure +These checks focus on the integrity of the project's dependencies, internal tools, and documentation. +* [`bins`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/bins/index.html): Prevent stray binaries from being checked into the source tree. +* [`fluent_alphabetical`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/fluent_alphabetical/index.html) / [`fluent_period`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/fluent_period/index.html) / [`fluent_used`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/fluent_used/index.html): Various checks related to [Fluent](https://github.com/projectfluent) for localization and natural language translation. +* [`deps`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/deps/index.html) / [`extdeps`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/extdeps/index.html): Check for valid licenses and sources for external dependencies. +* [`gcc_submodule`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/gcc_submodule/index.html): Check that the `src/gcc` submodule version is valid. +* [`triagebot`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/triagebot/index.html): Check to ensure paths mentioned in `triagebot.toml` exist in the project. +* [`x_version`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/x_version/index.html): Validates the current version of the `x` tool. + +* [`edition`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/edition/index.html) / [`features`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/features/index.html): Check for a valid Rust edition and proper ordering of unstable features. +* [`rustdoc_css_themes`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/rustdoc_css_themes/index.html) / [`rustdoc_templates`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/rustdoc_templates/index.html): Verify that Rust documentation templates and themes are correct. +* [`unstable_book`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/unstable_book/index.html): Synchronizes the unstable book with unstable features. +### Testing +These checks ensure that tests are correctly structured, cleaned up, and free of common errors. +* [`tests_placement`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/tests_placement/index.html) / [`unit_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/unit_tests/index.html): Verify that tests are located in the correct directories and are not using improper attributes. +* [`known_bug`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/known_bug/index.html) / [`unknown_revision`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/unknown_revision/index.html): Ensure that test directives and annotations are used correctly. +* [`debug_artifacts`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/debug_artifacts/index.html) / [`mir_opt_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/mir_opt_tests/index.html): Prevent unnecessary artifacts and stale files in test directories. +* [`tests_revision_unpaired_stdout_stderr`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/tests_revision_unpaired_stdout_stderr/index.html) / [`ui_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/ui_tests/index.html): Check for unpaired or stray test output files. +* [`target_specific_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/target_specific_tests/index.html): Check to ensure that all target specific tests (those that require a --target flag) also require the pre-requisite LLVM components to run. +* [`rustdoc_gui_tests`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/rustdoc_gui_tests/index.html): Checks that rustdoc gui tests start with a small description +* [`rustdoc_json`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/rustdoc_json/index.html): Verify that `FORMAT_VERSION` is in sync with `rust-json-types`. +## Using Tidy + +Tidy is used in a number of different ways. +* Every time `./x test` is used tidy will run automatically. + +* On every pull request, tidy will run automatically during CI checks. +* Optionally, with the use of git-hooks, tidy can run locally on every push. This can be setup with `./x setup`. See the [rustc-dev-guide](https://rustc-dev-guide.rust-lang.org/building/suggested.html#installing-a-pre-push-hook) for more information. + +You can run tidy manually with: + +`./x test tidy` + +To first run the relevant formatter and then run tidy you can add `--bless`. + +`./x test tidy --bless` +### Extra Checks +[`extra_checks`](https://doc.rust-lang.org/nightly/nightly-rustc/tidy/extra_checks/index.html) are optional checks primarily focused on other file types and programming languages. + +Example usage: + +`./x test tidy --extra-checks=py,cpp,js,spellcheck` + +All options for `--extra-checks`: +* `cpp`, `cpp:fmt` +* `py`, `py:lint`, `py:fmt` +* `js`, `js:lint`, `js:fmt`, `js:typecheck` +* `shell`, `shell:lint` +* `spellcheck` + +Default values for tidy's `extra-checks` can be set in `bootstrap.toml`. For example, `build.tidy-extra-checks = "js,py"`. + +Any argument without a suffix (eg. `py` or `js`) will include all possible checks. For example, `--extra-checks=js` is the same as `extra-checks=js:lint,js:fmt,js:typecheck`. + +Any argument can be prefixed with `auto:` to only run if relevant files are modified (eg. `--extra-checks=auto:py`). + +A specific configuration file or folder can be passed to tidy after a double dash (`--extra-checks=py -- foo.py`) + +## Tidy Directives + +Tidy directives are special comments that help tidy operate. + +Tidy directives can be used in the following types of comments: +* `// ` +* `# ` +* `/* {...} */` +* `<!-- {...} -->` + +You might find yourself needing to ignore a specific tidy style check and can do so with: +* `ignore-tidy-cr` +* `ignore-tidy-undocumented-unsafe` +* `ignore-tidy-tab` +* `ignore-tidy-linelength` +* `ignore-tidy-filelength` + +* `ignore-tidy-end-whitespace` +* `ignore-tidy-trailing-newlines` +* `ignore-tidy-leading-newlines` +* `ignore-tidy-copyright` +* `ignore-tidy-dbg` +* `ignore-tidy-odd-backticks` +* `ignore-tidy-todo` + +Some checks, like `alphabetical`, require a tidy directive to use: +``` +// tidy-alphabetical-start +fn aaa() {} +fn eee() {} +fn z() {} +// tidy-alphabetical-end +``` +<!--ignore-tidy-todo-->While not exactly a tidy directive, // TODO will fail tidy and make sure you can't merge a PR with unfinished work. + +### Test Specific Directives + +`target-specific-tests` can be ignored with `// ignore-tidy-target-specific-tests` + +Tidy's `unknown_revision` check can be suppressed by adding the revision name to `//@ unused-revision-names:{revision}` or with `//@ unused-revision-names:*`. diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 5b8b44429bb..991ad55809c 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -53,6 +53,7 @@ const EXCEPTION_PATHS: &[&str] = &[ // core::ffi contains platform-specific type and linkage configuration "library/core/src/ffi/mod.rs", "library/core/src/ffi/primitives.rs", + "library/core/src/os", // Platform-specific public interfaces "library/std/src/sys", // Platform-specific code for std lives here. "library/std/src/os", // Platform-specific public interfaces // Temporary `std` exceptions diff --git a/tests/assembly-llvm/riscv-soft-abi-with-float-features.rs b/tests/assembly-llvm/riscv-soft-abi-with-float-features.rs index 72cbd3841c1..085ea9facd0 100644 --- a/tests/assembly-llvm/riscv-soft-abi-with-float-features.rs +++ b/tests/assembly-llvm/riscv-soft-abi-with-float-features.rs @@ -2,9 +2,6 @@ //@ assembly-output: emit-asm //@ compile-flags: --target riscv64imac-unknown-none-elf -Ctarget-feature=+f,+d //@ needs-llvm-components: riscv -//@ revisions: LLVM-PRE-20 LLVM-POST-20 -//@ [LLVM-PRE-20] max-llvm-major-version: 19 -//@ [LLVM-POST-20] min-llvm-version: 20 #![feature(no_core, lang_items, f16)] #![crate_type = "lib"] @@ -28,11 +25,8 @@ pub extern "C" fn read_f16(x: &f16) -> f16 { // CHECK-LABEL: read_f32 #[no_mangle] pub extern "C" fn read_f32(x: &f32) -> f32 { - // LLVM-PRE-20: flw fa5, 0(a0) - // LLVM-PRE-20-NEXT: fmv.x.w a0, fa5 - // LLVM-PRE-20-NEXT: ret - // LLVM-POST-20: lw a0, 0(a0) - // LLVM-POST-20-NEXT: ret + // CHECK: lw a0, 0(a0) + // CHECK-NEXT: ret *x } diff --git a/tests/assembly-llvm/x86_64-bigint-helpers.rs b/tests/assembly-llvm/x86_64-bigint-helpers.rs index c5efda58fd6..64aa0257238 100644 --- a/tests/assembly-llvm/x86_64-bigint-helpers.rs +++ b/tests/assembly-llvm/x86_64-bigint-helpers.rs @@ -2,7 +2,6 @@ //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -Copt-level=3 -C target-cpu=x86-64-v4 //@ compile-flags: -C llvm-args=-x86-asm-syntax=intel -//@ min-llvm-version: 20 #![no_std] #![feature(bigint_helper_methods)] diff --git a/tests/assembly-llvm/x86_64-cmp.rs b/tests/assembly-llvm/x86_64-cmp.rs index 26c9013d96f..1f1fe7fd005 100644 --- a/tests/assembly-llvm/x86_64-cmp.rs +++ b/tests/assembly-llvm/x86_64-cmp.rs @@ -1,12 +1,6 @@ -//@ revisions: LLVM-PRE-20-DEBUG LLVM-20-DEBUG LLVM-PRE-20-OPTIM LLVM-20-OPTIM -//@ [LLVM-PRE-20-DEBUG] compile-flags: -C opt-level=0 -//@ [LLVM-PRE-20-DEBUG] max-llvm-major-version: 19 -//@ [LLVM-20-DEBUG] compile-flags: -C opt-level=0 -//@ [LLVM-20-DEBUG] min-llvm-version: 20 -//@ [LLVM-PRE-20-OPTIM] compile-flags: -C opt-level=3 -//@ [LLVM-PRE-20-OPTIM] max-llvm-major-version: 19 -//@ [LLVM-20-OPTIM] compile-flags: -C opt-level=3 -//@ [LLVM-20-OPTIM] min-llvm-version: 20 +//@ revisions: DEBUG OPTIM +//@ [DEBUG] compile-flags: -C opt-level=0 +//@ [OPTIM] compile-flags: -C opt-level=3 //@ assembly-output: emit-asm //@ compile-flags: --crate-type=lib -C llvm-args=-x86-asm-syntax=intel //@ only-x86_64 @@ -19,61 +13,22 @@ use std::intrinsics::three_way_compare; #[no_mangle] // CHECK-LABEL: signed_cmp: pub fn signed_cmp(a: i16, b: i16) -> std::cmp::Ordering { - // LLVM-PRE-20-DEBUG: cmp - // LLVM-PRE-20-DEBUG: setg - // LLVM-PRE-20-DEBUG: and - // LLVM-PRE-20-DEBUG: cmp - // LLVM-PRE-20-DEBUG: setl - // LLVM-PRE-20-DEBUG: and - // LLVM-PRE-20-DEBUG: sub - // - // LLVM-20-DEBUG: sub - // LLVM-20-DEBUG: setl - // LLVM-20-DEBUG: setg - // LLVM-20-DEBUG: sub - // LLVM-20-DEBUG: ret - - // LLVM-PRE-20-OPTIM: xor - // LLVM-PRE-20-OPTIM: cmp - // LLVM-PRE-20-OPTIM: setne - // LLVM-PRE-20-OPTIM: mov - // LLVM-PRE-20-OPTIM: cmovge - // LLVM-PRE-20-OPTIM: ret - // - // LLVM-20-OPTIM: cmp - // LLVM-20-OPTIM: setl - // LLVM-20-OPTIM: setg - // LLVM-20-OPTIM: sub - // LLVM-20-OPTIM: ret + // DEBUG: sub + // OPTIM: cmp + // CHECK: setl + // CHECK: setg + // CHECK: sub + // CHECK: ret three_way_compare(a, b) } #[no_mangle] // CHECK-LABEL: unsigned_cmp: pub fn unsigned_cmp(a: u16, b: u16) -> std::cmp::Ordering { - // LLVM-PRE-20-DEBUG: cmp - // LLVM-PRE-20-DEBUG: seta - // LLVM-PRE-20-DEBUG: and - // LLVM-PRE-20-DEBUG: cmp - // LLVM-PRE-20-DEBUG: setb - // LLVM-PRE-20-DEBUG: and - // LLVM-PRE-20-DEBUG: sub - // - // LLVM-20-DEBUG: sub - // LLVM-20-DEBUG: seta - // LLVM-20-DEBUG: sbb - // LLVM-20-DEBUG: ret - - // LLVM-PRE-20-OPTIM: xor - // LLVM-PRE-20-OPTIM: cmp - // LLVM-PRE-20-OPTIM: setne - // LLVM-PRE-20-OPTIM: mov - // LLVM-PRE-20-OPTIM: cmovae - // LLVM-PRE-20-OPTIM: ret - // - // LLVM-20-OPTIM: cmp - // LLVM-20-OPTIM: seta - // LLVM-20-OPTIM: sbb - // LLVM-20-OPTIM: ret + // DEBUG: sub + // OPTIM: cmp + // CHECK: seta + // CHECK: sbb + // CHECK: ret three_way_compare(a, b) } diff --git a/tests/codegen-llvm/asm/riscv-clobbers.rs b/tests/codegen-llvm/asm/riscv-clobbers.rs index e55b6731098..0f235ddcdcc 100644 --- a/tests/codegen-llvm/asm/riscv-clobbers.rs +++ b/tests/codegen-llvm/asm/riscv-clobbers.rs @@ -17,7 +17,7 @@ extern crate minicore; use minicore::*; // CHECK-LABEL: @flags_clobber -// CHECK: call void asm sideeffect "", "~{vtype},~{vl},~{vxsat},~{vxrm}"() +// CHECK: call void asm sideeffect "", "~{fflags},~{vtype},~{vl},~{vxsat},~{vxrm}"() #[no_mangle] pub unsafe fn flags_clobber() { asm!("", options(nostack, nomem)); diff --git a/tests/codegen-llvm/auxiliary/darwin_objc_aux.rs b/tests/codegen-llvm/auxiliary/darwin_objc_aux.rs new file mode 100644 index 00000000000..3c35d003c8a --- /dev/null +++ b/tests/codegen-llvm/auxiliary/darwin_objc_aux.rs @@ -0,0 +1,27 @@ +#![crate_type = "lib"] +#![feature(darwin_objc)] + +use std::os::darwin::objc; + +#[link(name = "Foundation", kind = "framework")] +unsafe extern "C" {} + +#[inline(always)] +pub fn inline_get_object_class() -> objc::Class { + objc::class!("NSObject") +} + +#[inline(always)] +pub fn inline_get_alloc_selector() -> objc::SEL { + objc::selector!("alloc") +} + +#[inline(never)] +pub fn never_inline_get_string_class() -> objc::Class { + objc::class!("NSString") +} + +#[inline(never)] +pub fn never_inline_get_init_selector() -> objc::SEL { + objc::selector!("init") +} diff --git a/tests/codegen-llvm/comparison-operators-2-struct.rs b/tests/codegen-llvm/comparison-operators-2-struct.rs index e179066ebfd..d44f92f511b 100644 --- a/tests/codegen-llvm/comparison-operators-2-struct.rs +++ b/tests/codegen-llvm/comparison-operators-2-struct.rs @@ -1,5 +1,4 @@ //@ compile-flags: -C opt-level=1 -//@ min-llvm-version: 20 // The `derive(PartialOrd)` for a 2-field type doesn't override `lt`/`le`/`gt`/`ge`. // This double-checks that the `Option<Ordering>` intermediate values used diff --git a/tests/codegen-llvm/comparison-operators-2-tuple.rs b/tests/codegen-llvm/comparison-operators-2-tuple.rs index 6a7e489c82d..37a7c5dfdaf 100644 --- a/tests/codegen-llvm/comparison-operators-2-tuple.rs +++ b/tests/codegen-llvm/comparison-operators-2-tuple.rs @@ -1,5 +1,4 @@ //@ compile-flags: -C opt-level=1 -Z merge-functions=disabled -//@ min-llvm-version: 20 #![crate_type = "lib"] diff --git a/tests/codegen-llvm/darwin-no-objc.rs b/tests/codegen-llvm/darwin-no-objc.rs new file mode 100644 index 00000000000..fda3671fb6d --- /dev/null +++ b/tests/codegen-llvm/darwin-no-objc.rs @@ -0,0 +1,52 @@ +// Test that we don't generate Objective-C definitions or image info unnecessarily. + +//@ add-core-stubs +//@ revisions: i686_apple_darwin +//@ [i686_apple_darwin] compile-flags: --target i686-apple-darwin +//@ [i686_apple_darwin] needs-llvm-components: x86 +//@ revisions: x86_64_macos +//@ [x86_64_macos] compile-flags: --target x86_64-apple-darwin +//@ [x86_64_macos] needs-llvm-components: x86 +//@ revisions: aarch64_macos +//@ [aarch64_macos] compile-flags: --target aarch64-apple-darwin +//@ [aarch64_macos] needs-llvm-components: aarch64 +//@ revisions: i386_ios +//@ [i386_ios] compile-flags: --target i386-apple-ios +//@ [i386_ios] needs-llvm-components: x86 +//@ revisions: x86_64_ios +//@ [x86_64_ios] compile-flags: --target x86_64-apple-ios +//@ [x86_64_ios] needs-llvm-components: x86 +//@ revisions: armv7s_ios +//@ [armv7s_ios] compile-flags: --target armv7s-apple-ios +//@ [armv7s_ios] needs-llvm-components: arm +//@ revisions: aarch64_ios +//@ [aarch64_ios] compile-flags: --target aarch64-apple-ios +//@ [aarch64_ios] needs-llvm-components: aarch64 +//@ revisions: aarch64_ios_sim +//@ [aarch64_ios_sim] compile-flags: --target aarch64-apple-ios-sim +//@ [aarch64_ios_sim] needs-llvm-components: aarch64 + +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub fn foo() {} + +// CHECK-NOT: %struct._class_t +// CHECK-NOT: %struct._objc_module +// CHECK-NOT: @OBJC_CLASS_NAME_ +// CHECK-NOT: @"OBJC_CLASS_$_{{[0-9A-Z_a-z]+}}" +// CHECK-NOT: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" +// CHECK-NOT: @OBJC_METH_VAR_NAME_ +// CHECK-NOT: @OBJC_SELECTOR_REFERENCES_ +// CHECK-NOT: @OBJC_MODULES + +// CHECK-NOT: !"Objective-C Version" +// CHECK-NOT: !"Objective-C Image Info Version" +// CHECK-NOT: !"Objective-C Image Info Section" +// CHECK-NOT: !"Objective-C Is Simulated" +// CHECK-NOT: !"Objective-C Class Properties" diff --git a/tests/codegen-llvm/darwin-objc-abi-v1.rs b/tests/codegen-llvm/darwin-objc-abi-v1.rs new file mode 100644 index 00000000000..0fc1de9332a --- /dev/null +++ b/tests/codegen-llvm/darwin-objc-abi-v1.rs @@ -0,0 +1,100 @@ +// ignore-tidy-linelength +//@ add-core-stubs +//@ revisions: i686_apple_darwin +//@ [i686_apple_darwin] compile-flags: --target i686-apple-darwin +//@ [i686_apple_darwin] needs-llvm-components: x86 + +#![crate_type = "lib"] +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub fn get_class() -> *mut () { + unsafe extern "C" { + #[rustc_objc_class = "MyClass"] + safe static VAL: *mut (); + } + VAL +} + +#[no_mangle] +pub fn get_class_again() -> *mut () { + // Codegen should de-duplicate this class with the one from get_class above. + unsafe extern "C" { + #[rustc_objc_class = "MyClass"] + safe static VAL: *mut (); + } + VAL +} + +#[no_mangle] +pub fn get_selector() -> *mut () { + unsafe extern "C" { + #[rustc_objc_selector = "myMethod"] + safe static VAL: *mut (); + } + VAL +} + +#[no_mangle] +pub fn get_selector_again() -> *mut () { + // Codegen should de-duplicate this selector with the one from get_selector above. + unsafe extern "C" { + #[rustc_objc_selector = "myMethod"] + safe static VAL: *mut (); + } + VAL +} + +#[no_mangle] +pub fn get_other_class() -> *mut () { + unsafe extern "C" { + #[rustc_objc_class = "OtherClass"] + safe static VAL: *mut (); + } + VAL +} + +#[no_mangle] +pub fn get_other_selector() -> *mut () { + unsafe extern "C" { + #[rustc_objc_selector = "otherMethod"] + safe static VAL: *mut (); + } + VAL +} + +// CHECK: %struct._objc_module = type { i32, i32, ptr, ptr } + +// CHECK: @OBJC_CLASS_NAME_.{{[0-9]+}} = private unnamed_addr constant [8 x i8] c"MyClass\00", section "__TEXT,__cstring,cstring_literals", align 1 +// CHECK: @OBJC_CLASS_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, section "__OBJC,__cls_refs,literal_pointers,no_dead_strip", align 4 +// CHECK-NOT: @OBJC_CLASS_NAME_ +// CHECK-NOT: @OBJC_CLASS_REFERENCES_ + +// CHECK: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__cstring,cstring_literals", align 1 +// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = private externally_initialized global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__OBJC,__message_refs,literal_pointers,no_dead_strip", align 4 +// CHECK-NOT: @OBJC_METH_VAR_NAME_ +// CHECK-NOT: @OBJC_SELECTOR_REFERENCES_ + +// CHECK: @OBJC_CLASS_NAME_.{{[0-9]+}} = private unnamed_addr constant [11 x i8] c"OtherClass\00", section "__TEXT,__cstring,cstring_literals", align 1 +// CHECK: @OBJC_CLASS_REFERENCES_.{{[0-9]+}} = private global ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, section "__OBJC,__cls_refs,literal_pointers,no_dead_strip", align 4 + +// CHECK: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [12 x i8] c"otherMethod\00", section "__TEXT,__cstring,cstring_literals", align 1 +// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = private externally_initialized global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__OBJC,__message_refs,literal_pointers,no_dead_strip", align 4 + +// CHECK: @OBJC_CLASS_NAME_.{{[0-9]+}} = private unnamed_addr constant [1 x i8] zeroinitializer, section "__TEXT,__cstring,cstring_literals", align 1 +// CHECK: @OBJC_MODULES = private global %struct._objc_module { i32 7, i32 16, ptr @OBJC_CLASS_NAME_.{{[0-9]+}}, ptr null }, section "__OBJC,__module_info,regular,no_dead_strip", align 4 + +// CHECK: load ptr, ptr @OBJC_CLASS_REFERENCES_.{{[0-9]+}}, align 4 +// CHECK: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 4 +// CHECK: load ptr, ptr @OBJC_CLASS_REFERENCES_.{{[0-9]+}}, align 4 +// CHECK: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 4 + +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Version", i32 1} +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__OBJC,__image_info,regular"} +// CHECK-NOT: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} diff --git a/tests/codegen-llvm/darwin-objc-abi-v2.rs b/tests/codegen-llvm/darwin-objc-abi-v2.rs new file mode 100644 index 00000000000..f142371d582 --- /dev/null +++ b/tests/codegen-llvm/darwin-objc-abi-v2.rs @@ -0,0 +1,185 @@ +// ignore-tidy-linelength +//@ add-core-stubs +//@ revisions: x86_64_macos +//@ [x86_64_macos] compile-flags: --target x86_64-apple-darwin +//@ [x86_64_macos] needs-llvm-components: x86 +//@ revisions: aarch64_macos +//@ [aarch64_macos] compile-flags: --target aarch64-apple-darwin +//@ [aarch64_macos] needs-llvm-components: aarch64 +//@ revisions: i386_ios +//@ [i386_ios] compile-flags: --target i386-apple-ios +//@ [i386_ios] needs-llvm-components: x86 +//@ revisions: x86_64_ios +//@ [x86_64_ios] compile-flags: --target x86_64-apple-ios +//@ [x86_64_ios] needs-llvm-components: x86 +//@ revisions: armv7s_ios +//@ [armv7s_ios] compile-flags: --target armv7s-apple-ios +//@ [armv7s_ios] needs-llvm-components: arm +//@ revisions: aarch64_ios +//@ [aarch64_ios] compile-flags: --target aarch64-apple-ios +//@ [aarch64_ios] needs-llvm-components: aarch64 +//@ revisions: aarch64_ios_sim +//@ [aarch64_ios_sim] compile-flags: --target aarch64-apple-ios-sim +//@ [aarch64_ios_sim] needs-llvm-components: aarch64 + +#![crate_type = "lib"] +#![feature(no_core, lang_items, rustc_attrs)] +#![no_core] + +extern crate minicore; +use minicore::*; + +#[no_mangle] +pub fn get_class() -> *mut () { + unsafe extern "C" { + #[rustc_objc_class = "MyClass"] + safe static VAL: *mut (); + } + VAL +} + +#[no_mangle] +pub fn get_class_again() -> *mut () { + // Codegen should de-duplicate this class with the one from get_class above. + unsafe extern "C" { + #[rustc_objc_class = "MyClass"] + safe static VAL: *mut (); + } + VAL +} + +#[no_mangle] +pub fn get_selector() -> *mut () { + unsafe extern "C" { + #[rustc_objc_selector = "myMethod"] + safe static VAL: *mut (); + } + VAL +} + +#[no_mangle] +pub fn get_selector_again() -> *mut () { + // Codegen should de-duplicate this selector with the one from get_selector above. + unsafe extern "C" { + #[rustc_objc_selector = "myMethod"] + safe static VAL: *mut (); + } + VAL +} + +#[no_mangle] +pub fn get_other_class() -> *mut () { + unsafe extern "C" { + #[rustc_objc_class = "OtherClass"] + safe static VAL: *mut (); + } + VAL +} + +#[no_mangle] +pub fn get_other_selector() -> *mut () { + unsafe extern "C" { + #[rustc_objc_selector = "otherMethod"] + safe static VAL: *mut (); + } + VAL +} + +// CHECK: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } + +// CHECK: @"OBJC_CLASS_$_MyClass" = external global %struct._class_t +// CHECK: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_MyClass", section "__DATA,__objc_classrefs,regular,no_dead_strip", +// x86_64_macos-SAME: align 8 +// aarch64_macos-SAME: align 8 +// i386_ios-SAME: align 4 +// x86_64_ios-SAME: align 8 +// armv7s_ios-SAME: align 4 +// aarch64_ios-SAME: align 8 +// aarch64_ios_sim-SAME: align 8 +// CHECK-NOT: @"OBJC_CLASS_$_MyClass" +// CHECK-NOT: @"OBJC_CLASSLIST_REFERENCES_$_ + +// CHECK: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [9 x i8] c"myMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal externally_initialized global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip", +// x86_64_macos-SAME: align 8 +// aarch64_macos-SAME: align 8 +// i386_ios-SAME: align 4 +// x86_64_ios-SAME: align 8 +// armv7s_ios-SAME: align 4 +// aarch64_ios-SAME: align 8 +// aarch64_ios_sim-SAME: align 8 +// CHECK-NOT: @OBJC_METH_VAR_NAME_ +// CHECK-NOT: @OBJC_SELECTOR_REFERENCES_ + +// CHECK: @"OBJC_CLASS_$_OtherClass" = external global %struct._class_t +// CHECK: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_OtherClass", section "__DATA,__objc_classrefs,regular,no_dead_strip", +// x86_64_macos-SAME: align 8 +// aarch64_macos-SAME: align 8 +// i386_ios-SAME: align 4 +// x86_64_ios-SAME: align 8 +// armv7s_ios-SAME: align 4 +// aarch64_ios-SAME: align 8 +// aarch64_ios_sim-SAME: align 8 + +// CHECK: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [12 x i8] c"otherMethod\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal externally_initialized global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip", +// x86_64_macos-SAME: align 8 +// aarch64_macos-SAME: align 8 +// i386_ios-SAME: align 4 +// x86_64_ios-SAME: align 8 +// armv7s_ios-SAME: align 4 +// aarch64_ios-SAME: align 8 +// aarch64_ios_sim-SAME: align 8 + +// CHECK-NOT: @OBJC_CLASS_NAME_ +// CHECK-NOT: @OBJC_MODULES + +// CHECK: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", +// x86_64_macos-SAME: align 8 +// aarch64_macos-SAME: align 8 +// i386_ios-SAME: align 4 +// x86_64_ios-SAME: align 8 +// armv7s_ios-SAME: align 4 +// aarch64_ios-SAME: align 8 +// aarch64_ios_sim-SAME: align 8 + +// CHECK: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, +// x86_64_macos-SAME: align 8 +// aarch64_macos-SAME: align 8 +// i386_ios-SAME: align 4 +// x86_64_ios-SAME: align 8 +// armv7s_ios-SAME: align 4 +// aarch64_ios-SAME: align 8 +// aarch64_ios_sim-SAME: align 8 + +// CHECK: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", +// x86_64_macos-SAME: align 8 +// aarch64_macos-SAME: align 8 +// i386_ios-SAME: align 4 +// x86_64_ios-SAME: align 8 +// armv7s_ios-SAME: align 4 +// aarch64_ios-SAME: align 8 +// aarch64_ios_sim-SAME: align 8 + +// CHECK: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, +// x86_64_macos-SAME: align 8 +// aarch64_macos-SAME: align 8 +// i386_ios-SAME: align 4 +// x86_64_ios-SAME: align 8 +// armv7s_ios-SAME: align 4 +// aarch64_ios-SAME: align 8 +// aarch64_ios_sim-SAME: align 8 + +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Version", i32 2} +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} + +// x86_64_macos-NOT: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// aarch64_macos-NOT: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// i386_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// x86_64_ios: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// armv7s_ios-NOT: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// aarch64_ios-NOT: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// aarch64_ios_sim: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} + +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} diff --git a/tests/codegen-llvm/darwin-objc-cross-crate.rs b/tests/codegen-llvm/darwin-objc-cross-crate.rs new file mode 100644 index 00000000000..74ad9a27346 --- /dev/null +++ b/tests/codegen-llvm/darwin-objc-cross-crate.rs @@ -0,0 +1,58 @@ +// Test that Objective-C class and selector references inlined across crates +// get defined in this CGU but non-inline references don't. + +// ignore-tidy-linelength +//@ aux-build: darwin_objc_aux.rs +//@ revisions: x86_64_macos aarch64_macos +//@ [x86_64_macos] only-x86_64-apple-darwin +//@ [aarch64_macos] only-aarch64-apple-darwin + +#![crate_type = "lib"] +#![feature(darwin_objc)] + +use std::os::darwin::objc; + +extern crate darwin_objc_aux as aux; + +#[no_mangle] +pub fn get_object_class() -> objc::Class { + aux::inline_get_object_class() +} + +#[no_mangle] +pub fn get_alloc_selector() -> objc::SEL { + aux::inline_get_alloc_selector() +} + +#[no_mangle] +pub fn get_string_class() -> objc::Class { + aux::never_inline_get_string_class() +} + +#[no_mangle] +pub fn get_init_selector() -> objc::SEL { + aux::never_inline_get_init_selector() +} + +// CHECK: %struct._class_t = type { ptr, ptr, ptr, ptr, ptr } + +// CHECK: @"OBJC_CLASS_$_NSObject" = external global %struct._class_t +// CHECK: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_NSObject", section "__DATA,__objc_classrefs,regular,no_dead_strip", align 8 + +// CHECK: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [6 x i8] c"alloc\00", section "__TEXT,__objc_methname,cstring_literals", align 1 +// CHECK: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal externally_initialized global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}}, section "__DATA,__objc_selrefs,literal_pointers,no_dead_strip", align 8 + +// CHECK-NOT: @"OBJC_CLASS_$_NSString" = external global %struct._class_t +// CHECK-NOT: @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}" = internal global ptr @"OBJC_CLASS_$_NSString" + +// CHECK-NOT: @OBJC_METH_VAR_NAME_.{{[0-9]+}} = private unnamed_addr constant [5 x i8] c"init\00" +// CHECK-NOT: @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}} = internal externally_initialized global ptr @OBJC_METH_VAR_NAME_.{{[0-9]+}} + +// CHECK: load ptr, ptr @"OBJC_CLASSLIST_REFERENCES_$_.{{[0-9]+}}", align 8 +// CHECK: load ptr, ptr @OBJC_SELECTOR_REFERENCES_.{{[0-9]+}}, align 8 + +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Version", i32 2} +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Version", i32 0} +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Image Info Section", !"__DATA,__objc_imageinfo,regular,no_dead_strip"} +// CHECK-NOT: !{{[0-9]+}} = !{i32 1, !"Objective-C Is Simulated", i32 32} +// CHECK: !{{[0-9]+}} = !{i32 1, !"Objective-C Class Properties", i32 64} diff --git a/tests/codegen-llvm/enum/enum-aggregate.rs b/tests/codegen-llvm/enum/enum-aggregate.rs index f58d7ef12b6..7d450a89e2e 100644 --- a/tests/codegen-llvm/enum/enum-aggregate.rs +++ b/tests/codegen-llvm/enum/enum-aggregate.rs @@ -1,5 +1,4 @@ //@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes -//@ min-llvm-version: 19 //@ only-64bit #![crate_type = "lib"] diff --git a/tests/codegen-llvm/enum/enum-discriminant-eq.rs b/tests/codegen-llvm/enum/enum-discriminant-eq.rs index a1ab5e5c6e2..68cd58643e8 100644 --- a/tests/codegen-llvm/enum/enum-discriminant-eq.rs +++ b/tests/codegen-llvm/enum/enum-discriminant-eq.rs @@ -1,5 +1,4 @@ //@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled -//@ min-llvm-version: 20 //@ only-64bit //@ revisions: LLVM20 LLVM21 //@ [LLVM21] min-llvm-version: 21 diff --git a/tests/codegen-llvm/integer-cmp.rs b/tests/codegen-llvm/integer-cmp.rs index 812fa8e4a42..2233a575f8e 100644 --- a/tests/codegen-llvm/integer-cmp.rs +++ b/tests/codegen-llvm/integer-cmp.rs @@ -1,9 +1,6 @@ // This is test for more optimal Ord implementation for integers. // See <https://github.com/rust-lang/rust/issues/63758> for more info. -//@ revisions: llvm-pre-20 llvm-20 -//@ [llvm-20] min-llvm-version: 20 -//@ [llvm-pre-20] max-llvm-major-version: 19 //@ compile-flags: -C opt-level=3 -Zmerge-functions=disabled #![crate_type = "lib"] @@ -13,50 +10,29 @@ use std::cmp::Ordering; // CHECK-LABEL: @cmp_signed #[no_mangle] pub fn cmp_signed(a: i64, b: i64) -> Ordering { - // llvm-20: call{{.*}} i8 @llvm.scmp.i8.i64 - // llvm-pre-20: icmp slt - // llvm-pre-20: icmp ne - // llvm-pre-20: zext i1 - // llvm-pre-20: select i1 + // CHECK: call{{.*}} i8 @llvm.scmp.i8.i64 a.cmp(&b) } // CHECK-LABEL: @cmp_unsigned #[no_mangle] pub fn cmp_unsigned(a: u32, b: u32) -> Ordering { - // llvm-20: call{{.*}} i8 @llvm.ucmp.i8.i32 - // llvm-pre-20: icmp ult - // llvm-pre-20: icmp ne - // llvm-pre-20: zext i1 - // llvm-pre-20: select i1 + // CHECK: call{{.*}} i8 @llvm.ucmp.i8.i32 a.cmp(&b) } // CHECK-LABEL: @cmp_char #[no_mangle] pub fn cmp_char(a: char, b: char) -> Ordering { - // llvm-20: call{{.*}} i8 @llvm.ucmp.i8.i32 - // llvm-pre-20: icmp ult - // llvm-pre-20: icmp ne - // llvm-pre-20: zext i1 - // llvm-pre-20: select i1 + // CHECK: call{{.*}} i8 @llvm.ucmp.i8.i32 a.cmp(&b) } // CHECK-LABEL: @cmp_tuple #[no_mangle] pub fn cmp_tuple(a: (i16, u16), b: (i16, u16)) -> Ordering { - // llvm-20-DAG: call{{.*}} i8 @llvm.ucmp.i8.i16 - // llvm-20-DAG: call{{.*}} i8 @llvm.scmp.i8.i16 - // llvm-20: ret i8 - // llvm-pre-20: icmp slt - // llvm-pre-20: icmp ne - // llvm-pre-20: zext i1 - // llvm-pre-20: select i1 - // llvm-pre-20: icmp ult - // llvm-pre-20: icmp ne - // llvm-pre-20: zext i1 - // llvm-pre-20: select i1 - // llvm-pre-20: select i1 + // CHECK-DAG: call{{.*}} i8 @llvm.ucmp.i8.i16 + // CHECK-DAG: call{{.*}} i8 @llvm.scmp.i8.i16 + // CHECK: ret i8 a.cmp(&b) } diff --git a/tests/codegen-llvm/intrinsics/three_way_compare.rs b/tests/codegen-llvm/intrinsics/three_way_compare.rs index 95fcb636f7c..89bf69561e9 100644 --- a/tests/codegen-llvm/intrinsics/three_way_compare.rs +++ b/tests/codegen-llvm/intrinsics/three_way_compare.rs @@ -2,7 +2,6 @@ //@ [DEBUG] compile-flags: -C opt-level=0 //@ [OPTIM] compile-flags: -C opt-level=3 //@ compile-flags: -C no-prepopulate-passes -//@ min-llvm-version: 20 #![crate_type = "lib"] #![feature(core_intrinsics)] diff --git a/tests/codegen-llvm/issues/and-masked-comparison-131162.rs b/tests/codegen-llvm/issues/and-masked-comparison-131162.rs index bdf021092fd..fc4b0341a31 100644 --- a/tests/codegen-llvm/issues/and-masked-comparison-131162.rs +++ b/tests/codegen-llvm/issues/and-masked-comparison-131162.rs @@ -1,5 +1,4 @@ //@ compile-flags: -Copt-level=3 -//@ min-llvm-version: 20 #![crate_type = "lib"] diff --git a/tests/codegen-llvm/issues/issue-101082.rs b/tests/codegen-llvm/issues/issue-101082.rs index 8d15921ddb4..0c1f90f951a 100644 --- a/tests/codegen-llvm/issues/issue-101082.rs +++ b/tests/codegen-llvm/issues/issue-101082.rs @@ -1,6 +1,5 @@ //@ compile-flags: -Copt-level=3 //@ revisions: host x86-64 x86-64-v3 -//@ min-llvm-version: 20 //@[host] ignore-x86_64 diff --git a/tests/codegen-llvm/issues/issue-129795.rs b/tests/codegen-llvm/issues/issue-129795.rs index dc64ee35c97..7a928389fab 100644 --- a/tests/codegen-llvm/issues/issue-129795.rs +++ b/tests/codegen-llvm/issues/issue-129795.rs @@ -1,5 +1,4 @@ //@ compile-flags: -Copt-level=3 -//@ min-llvm-version: 20 #![crate_type = "lib"] // Ensure that a modulo operation with an operand that is known to be diff --git a/tests/codegen-llvm/issues/iter-max-no-unwrap-failed-129583.rs b/tests/codegen-llvm/issues/iter-max-no-unwrap-failed-129583.rs index 4d3fa4993ef..4c4eebeabb5 100644 --- a/tests/codegen-llvm/issues/iter-max-no-unwrap-failed-129583.rs +++ b/tests/codegen-llvm/issues/iter-max-no-unwrap-failed-129583.rs @@ -3,7 +3,6 @@ // use a larger value to prevent unrolling. //@ compile-flags: -Copt-level=3 -//@ min-llvm-version: 20 #![crate_type = "lib"] diff --git a/tests/codegen-llvm/issues/looping-over-ne-bytes-133528.rs b/tests/codegen-llvm/issues/looping-over-ne-bytes-133528.rs index 35acf765d69..b686f8c4b3a 100644 --- a/tests/codegen-llvm/issues/looping-over-ne-bytes-133528.rs +++ b/tests/codegen-llvm/issues/looping-over-ne-bytes-133528.rs @@ -1,5 +1,4 @@ //@ compile-flags: -Copt-level=3 -//@ min-llvm-version: 20 #![crate_type = "lib"] /// Ensure the function is properly optimized diff --git a/tests/codegen-llvm/option-niche-eq.rs b/tests/codegen-llvm/option-niche-eq.rs index 3900cb79aa2..e9c3fa2407e 100644 --- a/tests/codegen-llvm/option-niche-eq.rs +++ b/tests/codegen-llvm/option-niche-eq.rs @@ -1,5 +1,4 @@ //@ revisions: REGULAR LLVM21 -//@ min-llvm-version: 20 //@ compile-flags: -Copt-level=3 -Zmerge-functions=disabled //@ [LLVM21] min-llvm-version: 21 #![crate_type = "lib"] diff --git a/tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs b/tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs index 561f081c700..ffff4b35994 100644 --- a/tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs +++ b/tests/codegen-llvm/rust-abi-arch-specific-adjustment.rs @@ -1,15 +1,19 @@ +//@ add-core-stubs //@ compile-flags: -Copt-level=3 -C no-prepopulate-passes //@ revisions: riscv64 loongarch64 -//@[riscv64] only-riscv64 //@[riscv64] compile-flags: --target riscv64gc-unknown-linux-gnu //@[riscv64] needs-llvm-components: riscv -//@[loongarch64] only-loongarch64 //@[loongarch64] compile-flags: --target loongarch64-unknown-linux-gnu //@[loongarch64] needs-llvm-components: loongarch #![crate_type = "lib"] +#![feature(no_core)] +#![no_core] + +extern crate minicore; +use minicore::*; #[no_mangle] // riscv64: define noundef i8 @arg_attr_u8(i8 noundef zeroext %x) diff --git a/tests/codegen-llvm/slice-last-elements-optimization.rs b/tests/codegen-llvm/slice-last-elements-optimization.rs index d982cda709d..77fc1d21cd9 100644 --- a/tests/codegen-llvm/slice-last-elements-optimization.rs +++ b/tests/codegen-llvm/slice-last-elements-optimization.rs @@ -1,5 +1,4 @@ //@ compile-flags: -Copt-level=3 -//@ min-llvm-version: 20 #![crate_type = "lib"] // This test verifies that LLVM 20 properly optimizes the bounds check diff --git a/tests/codegen-llvm/swap-small-types.rs b/tests/codegen-llvm/swap-small-types.rs index 7aa613ae9c2..0799ff76331 100644 --- a/tests/codegen-llvm/swap-small-types.rs +++ b/tests/codegen-llvm/swap-small-types.rs @@ -1,6 +1,5 @@ //@ compile-flags: -Copt-level=3 -Z merge-functions=disabled //@ only-x86_64 -//@ min-llvm-version: 20 //@ ignore-std-debug-assertions (`ptr::swap_nonoverlapping` has one which blocks some optimizations) #![crate_type = "lib"] diff --git a/tests/codegen-llvm/try_question_mark_nop.rs b/tests/codegen-llvm/try_question_mark_nop.rs index 398c9a580bc..a09fa0a4901 100644 --- a/tests/codegen-llvm/try_question_mark_nop.rs +++ b/tests/codegen-llvm/try_question_mark_nop.rs @@ -1,9 +1,6 @@ //@ compile-flags: -Copt-level=3 -Z merge-functions=disabled //@ edition: 2021 //@ only-x86_64 -//@ revisions: NINETEEN TWENTY -//@[NINETEEN] exact-llvm-major-version: 19 -//@[TWENTY] min-llvm-version: 20 #![crate_type = "lib"] #![feature(try_blocks)] @@ -17,13 +14,9 @@ pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> { // CHECK: start: // CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i32 %0 to i1 - // NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %0, i32 0 - // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 [[SELECT]], 0 - // NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 %1, 1 - - // TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %1, i32 undef - // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0 - // TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 [[SELECT]], 1 + // CHECK-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i32 %1, i32 undef + // CHECK-NEXT: [[REG2:%.*]] = insertvalue { i32, i32 } poison, i32 %0, 0 + // CHECK-NEXT: [[REG3:%.*]] = insertvalue { i32, i32 } [[REG2]], i32 [[SELECT]], 1 // CHECK-NEXT: ret { i32, i32 } [[REG3]] match x { @@ -36,8 +29,8 @@ pub fn option_nop_match_32(x: Option<u32>) -> Option<u32> { #[no_mangle] pub fn option_nop_traits_32(x: Option<u32>) -> Option<u32> { // CHECK: start: - // TWENTY-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1 - // TWENTY-NEXT: select i1 %[[IS_SOME]], i32 %1, i32 undef + // CHECK-NEXT: %[[IS_SOME:.+]] = trunc nuw i32 %0 to i1 + // CHECK-NEXT: select i1 %[[IS_SOME]], i32 %1, i32 undef // CHECK-NEXT: insertvalue { i32, i32 } // CHECK-NEXT: insertvalue { i32, i32 } // CHECK-NEXT: ret { i32, i32 } @@ -96,13 +89,9 @@ pub fn option_nop_match_64(x: Option<u64>) -> Option<u64> { // CHECK: start: // CHECK-NEXT: [[TRUNC:%.*]] = trunc nuw i64 %0 to i1 - // NINETEEN-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %0, i64 0 - // NINETEEN-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 [[SELECT]], 0 - // NINETEEN-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 %1, 1 - - // TWENTY-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %1, i64 undef - // TWENTY-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 %0, 0 - // TWENTY-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 [[SELECT]], 1 + // CHECK-NEXT: [[SELECT:%.*]] = select i1 [[TRUNC]], i64 %1, i64 undef + // CHECK-NEXT: [[REG2:%.*]] = insertvalue { i64, i64 } poison, i64 %0, 0 + // CHECK-NEXT: [[REG3:%.*]] = insertvalue { i64, i64 } [[REG2]], i64 [[SELECT]], 1 // CHECK-NEXT: ret { i64, i64 } [[REG3]] match x { @@ -115,8 +104,8 @@ pub fn option_nop_match_64(x: Option<u64>) -> Option<u64> { #[no_mangle] pub fn option_nop_traits_64(x: Option<u64>) -> Option<u64> { // CHECK: start: - // TWENTY-NEXT: %[[TRUNC:[0-9]+]] = trunc nuw i64 %0 to i1 - // TWENTY-NEXT: %[[SEL:\.[0-9]+]] = select i1 %[[TRUNC]], i64 %1, i64 undef + // CHECK-NEXT: %[[TRUNC:[0-9]+]] = trunc nuw i64 %0 to i1 + // CHECK-NEXT: %[[SEL:\.[0-9]+]] = select i1 %[[TRUNC]], i64 %1, i64 undef // CHECK-NEXT: insertvalue { i64, i64 } // CHECK-NEXT: insertvalue { i64, i64 } // CHECK-NEXT: ret { i64, i64 } diff --git a/tests/codegen-llvm/union-aggregate.rs b/tests/codegen-llvm/union-aggregate.rs index aac66c5dcdd..7faa66804fe 100644 --- a/tests/codegen-llvm/union-aggregate.rs +++ b/tests/codegen-llvm/union-aggregate.rs @@ -1,5 +1,4 @@ //@ compile-flags: -Copt-level=0 -Cno-prepopulate-passes -//@ min-llvm-version: 19 //@ only-64bit #![crate_type = "lib"] diff --git a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir index 347e4119cd0..050aac7c3ff 100644 --- a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir +++ b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-abort.mir @@ -1,7 +1,7 @@ // MIR for `a::{closure#0}` 0 coroutine_drop_async fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>) -> Poll<()> { - debug _task_context => _19; + debug _task_context => _2; debug x => ((*(_1.0: &mut {async fn body of a<T>()})).0: T); let mut _0: std::task::Poll<()>; let _3: T; @@ -20,15 +20,14 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>) let mut _16: &mut impl std::future::Future<Output = ()>; let mut _17: std::pin::Pin<&mut impl std::future::Future<Output = ()>>; let mut _18: isize; - let mut _19: &mut std::task::Context<'_>; - let mut _20: u32; + let mut _19: u32; scope 1 { debug x => (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).0: T); } bb0: { - _20 = discriminant((*(_1.0: &mut {async fn body of a<T>()}))); - switchInt(move _20) -> [0: bb9, 3: bb12, 4: bb13, otherwise: bb14]; + _19 = discriminant((*(_1.0: &mut {async fn body of a<T>()}))); + switchInt(move _19) -> [0: bb9, 3: bb12, 4: bb13, otherwise: bb14]; } bb1: { diff --git a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir index b1cf5373f91..796e95ff3d8 100644 --- a/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir +++ b/tests/mir-opt/async_drop_live_dead.a-{closure#0}.coroutine_drop_async.0.panic-unwind.mir @@ -1,7 +1,7 @@ // MIR for `a::{closure#0}` 0 coroutine_drop_async fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>) -> Poll<()> { - debug _task_context => _19; + debug _task_context => _2; debug x => ((*(_1.0: &mut {async fn body of a<T>()})).0: T); let mut _0: std::task::Poll<()>; let _3: T; @@ -20,15 +20,14 @@ fn a::{closure#0}(_1: Pin<&mut {async fn body of a<T>()}>, _2: &mut Context<'_>) let mut _16: &mut impl std::future::Future<Output = ()>; let mut _17: std::pin::Pin<&mut impl std::future::Future<Output = ()>>; let mut _18: isize; - let mut _19: &mut std::task::Context<'_>; - let mut _20: u32; + let mut _19: u32; scope 1 { debug x => (((*(_1.0: &mut {async fn body of a<T>()})) as variant#4).0: T); } bb0: { - _20 = discriminant((*(_1.0: &mut {async fn body of a<T>()}))); - switchInt(move _20) -> [0: bb12, 2: bb18, 3: bb16, 4: bb17, otherwise: bb19]; + _19 = discriminant((*(_1.0: &mut {async fn body of a<T>()}))); + switchInt(move _19) -> [0: bb12, 2: bb18, 3: bb16, 4: bb17, otherwise: bb19]; } bb1: { diff --git a/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir index 7480324b177..2e2876cb3fc 100644 --- a/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.a-{closure#0}.coroutine_resume.0.mir @@ -10,19 +10,17 @@ } */ fn a::{closure#0}(_1: Pin<&mut {async fn body of a()}>, _2: &mut Context<'_>) -> Poll<()> { - debug _task_context => _4; + debug _task_context => _2; let mut _0: std::task::Poll<()>; let mut _3: (); - let mut _4: &mut std::task::Context<'_>; - let mut _5: u32; + let mut _4: u32; bb0: { - _5 = discriminant((*(_1.0: &mut {async fn body of a()}))); - switchInt(move _5) -> [0: bb1, 1: bb4, otherwise: bb5]; + _4 = discriminant((*(_1.0: &mut {async fn body of a()}))); + switchInt(move _4) -> [0: bb1, 1: bb4, otherwise: bb5]; } bb1: { - _4 = move _2; _3 = const (); goto -> bb3; } diff --git a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir index 9bff257e063..20fc4112ef2 100644 --- a/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/building/async_await.b-{closure#0}.coroutine_resume.0.mir @@ -1,7 +1,7 @@ // MIR for `b::{closure#0}` 0 coroutine_resume /* coroutine_layout = CoroutineLayout { field_tys: { - _0: CoroutineSavedTy { + _s0: CoroutineSavedTy { ty: Coroutine( DefId(0:5 ~ async_await[ccf8]::a::{closure#0}), [ @@ -18,7 +18,7 @@ }, ignore_for_traits: false, }, - _1: CoroutineSavedTy { + _s1: CoroutineSavedTy { ty: Coroutine( DefId(0:5 ~ async_await[ccf8]::a::{closure#0}), [ @@ -40,17 +40,17 @@ Unresumed(0): [], Returned (1): [], Panicked (2): [], - Suspend0 (3): [_0], - Suspend1 (4): [_1], + Suspend0 (3): [_s0], + Suspend1 (4): [_s1], }, storage_conflicts: BitMatrix(2x2) { - (_0, _0), - (_1, _1), + (_s0, _s0), + (_s1, _s1), }, } */ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> Poll<()> { - debug _task_context => _38; + debug _task_context => _2; let mut _0: std::task::Poll<()>; let _3: (); let mut _4: {async fn body of a()}; @@ -85,8 +85,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> let mut _35: &mut std::task::Context<'_>; let mut _36: (); let mut _37: (); - let mut _38: &mut std::task::Context<'_>; - let mut _39: u32; + let mut _38: u32; scope 1 { debug __awaitee => (((*(_1.0: &mut {async fn body of b()})) as variant#3).0: {async fn body of a()}); let _17: (); @@ -103,12 +102,11 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> } bb0: { - _39 = discriminant((*(_1.0: &mut {async fn body of b()}))); - switchInt(move _39) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb8]; + _38 = discriminant((*(_1.0: &mut {async fn body of b()}))); + switchInt(move _38) -> [0: bb1, 1: bb29, 3: bb27, 4: bb28, otherwise: bb8]; } bb1: { - _38 = move _2; StorageLive(_3); StorageLive(_4); StorageLive(_5); @@ -143,7 +141,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> StorageLive(_13); StorageLive(_14); StorageLive(_15); - _15 = copy _38; + _15 = copy _2; _14 = move _15; goto -> bb6; } @@ -198,7 +196,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> bb11: { StorageDead(_20); - _38 = move _19; + _2 = move _19; StorageDead(_19); _7 = const (); goto -> bb4; @@ -245,7 +243,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> StorageLive(_29); StorageLive(_30); StorageLive(_31); - _31 = copy _38; + _31 = copy _2; _30 = move _31; goto -> bb18; } @@ -295,7 +293,7 @@ fn b::{closure#0}(_1: Pin<&mut {async fn body of b()}>, _2: &mut Context<'_>) -> bb22: { StorageDead(_36); - _38 = move _35; + _2 = move _35; StorageDead(_35); _7 = const (); goto -> bb16; diff --git a/tests/mir-opt/building/coroutine.main-{closure#0}.StateTransform.after.mir b/tests/mir-opt/building/coroutine.main-{closure#0}.StateTransform.after.mir new file mode 100644 index 00000000000..d8fdb446135 --- /dev/null +++ b/tests/mir-opt/building/coroutine.main-{closure#0}.StateTransform.after.mir @@ -0,0 +1,207 @@ +// MIR for `main::{closure#0}` after StateTransform +/* coroutine_layout = CoroutineLayout { + field_tys: { + _s0: CoroutineSavedTy { + ty: std::string::String, + source_info: SourceInfo { + span: $DIR/coroutine.rs:18:6: 18:9 (#0), + scope: scope[0], + }, + ignore_for_traits: false, + }, + }, + variant_fields: { + Unresumed(0): [], + Returned (1): [], + Panicked (2): [], + Suspend0 (3): [_s0], + Suspend1 (4): [_s0], + }, + storage_conflicts: BitMatrix(1x1) { + (_s0, _s0), + }, +} */ + +fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}>, _2: String) -> CoroutineState<(&str, String, &Location<'_>), ()> { + debug arg => (((*(_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18})) as variant#4).0: std::string::String); + let mut _0: std::ops::CoroutineState<(&str, std::string::String, &std::panic::Location<'_>), ()>; + let _3: std::string::String; + let mut _4: (&str, std::string::String, &std::panic::Location<'_>); + let mut _5: std::string::String; + let mut _6: &std::string::String; + let mut _7: &std::panic::Location<'_>; + let _8: std::string::String; + let mut _9: (&str, std::string::String, &std::panic::Location<'_>); + let mut _10: &str; + let _11: &str; + let mut _12: std::string::String; + let mut _13: &std::string::String; + let mut _14: &std::panic::Location<'_>; + let _15: &std::panic::Location<'_>; + let mut _16: (); + let mut _17: u32; + let mut _18: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}; + let mut _19: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}; + let mut _20: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}; + let mut _21: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}; + let mut _22: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}; + let mut _23: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}; + let mut _24: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}; + let mut _25: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}; + + bb0: { + _18 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}); + _17 = discriminant((*_18)); + switchInt(move _17) -> [0: bb1, 1: bb19, 3: bb17, 4: bb18, otherwise: bb20]; + } + + bb1: { + _19 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}); + (((*_19) as variant#4).0: std::string::String) = move _2; + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + StorageLive(_6); + _20 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}); + _6 = &(((*_20) as variant#4).0: std::string::String); + _5 = <String as Clone>::clone(move _6) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_6); + StorageLive(_7); + _7 = Location::<'_>::caller() -> [return: bb3, unwind unreachable]; + } + + bb3: { + _4 = (const "first", move _5, move _7); + StorageDead(_7); + goto -> bb4; + } + + bb4: { + StorageDead(_5); + _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Yielded(move _4); + StorageDead(_3); + StorageDead(_4); + _21 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}); + discriminant((*_21)) = 3; + return; + } + + bb5: { + goto -> bb6; + } + + bb6: { + StorageDead(_4); + drop(_3) -> [return: bb7, unwind unreachable]; + } + + bb7: { + StorageDead(_3); + StorageLive(_8); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _11 = const "second"; + _10 = &(*_11); + StorageLive(_12); + StorageLive(_13); + _22 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}); + _13 = &(((*_22) as variant#4).0: std::string::String); + _12 = <String as Clone>::clone(move _13) -> [return: bb8, unwind unreachable]; + } + + bb8: { + StorageDead(_13); + StorageLive(_14); + StorageLive(_15); + _15 = Location::<'_>::caller() -> [return: bb9, unwind unreachable]; + } + + bb9: { + _14 = &(*_15); + _9 = (move _10, move _12, move _14); + StorageDead(_14); + goto -> bb10; + } + + bb10: { + StorageDead(_12); + StorageDead(_10); + _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Yielded(move _9); + StorageDead(_8); + StorageDead(_9); + StorageDead(_11); + StorageDead(_15); + _23 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}); + discriminant((*_23)) = 4; + return; + } + + bb11: { + goto -> bb12; + } + + bb12: { + StorageDead(_9); + drop(_8) -> [return: bb13, unwind unreachable]; + } + + bb13: { + StorageDead(_15); + StorageDead(_11); + StorageDead(_8); + _16 = const (); + _24 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}); + drop((((*_24) as variant#4).0: std::string::String)) -> [return: bb14, unwind unreachable]; + } + + bb14: { + goto -> bb16; + } + + bb15: { + _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Complete(move _16); + _25 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:18:5: 18:18}); + discriminant((*_25)) = 1; + return; + } + + bb16: { + goto -> bb15; + } + + bb17: { + StorageLive(_3); + StorageLive(_4); + _3 = move _2; + goto -> bb5; + } + + bb18: { + StorageLive(_8); + StorageLive(_9); + StorageLive(_11); + StorageLive(_15); + _8 = move _2; + goto -> bb11; + } + + bb19: { + assert(const false, "coroutine resumed after completion") -> [success: bb19, unwind unreachable]; + } + + bb20: { + unreachable; + } +} + +ALLOC0 (size: 6, align: 1) { + 73 65 63 6f 6e 64 │ second +} + +ALLOC1 (size: 5, align: 1) { + 66 69 72 73 74 │ first +} diff --git a/tests/mir-opt/building/coroutine.main-{closure#1}.StateTransform.after.mir b/tests/mir-opt/building/coroutine.main-{closure#1}.StateTransform.after.mir new file mode 100644 index 00000000000..dd17afad656 --- /dev/null +++ b/tests/mir-opt/building/coroutine.main-{closure#1}.StateTransform.after.mir @@ -0,0 +1,207 @@ +// MIR for `main::{closure#1}` after StateTransform +/* coroutine_layout = CoroutineLayout { + field_tys: { + _s0: CoroutineSavedTy { + ty: std::string::String, + source_info: SourceInfo { + span: $DIR/coroutine.rs:25:6: 25:9 (#0), + scope: scope[0], + }, + ignore_for_traits: false, + }, + }, + variant_fields: { + Unresumed(0): [], + Returned (1): [], + Panicked (2): [], + Suspend0 (3): [_s0], + Suspend1 (4): [_s0], + }, + storage_conflicts: BitMatrix(1x1) { + (_s0, _s0), + }, +} */ + +fn main::{closure#1}(_1: Pin<&mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}>, _2: String) -> CoroutineState<(&str, String, &Location<'_>), ()> { + debug arg => (((*(_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18})) as variant#4).0: std::string::String); + let mut _0: std::ops::CoroutineState<(&str, std::string::String, &std::panic::Location<'_>), ()>; + let _3: std::string::String; + let mut _4: (&str, std::string::String, &std::panic::Location<'_>); + let mut _5: std::string::String; + let mut _6: &std::string::String; + let mut _7: &std::panic::Location<'_>; + let _8: std::string::String; + let mut _9: (&str, std::string::String, &std::panic::Location<'_>); + let mut _10: &str; + let _11: &str; + let mut _12: std::string::String; + let mut _13: &std::string::String; + let mut _14: &std::panic::Location<'_>; + let _15: &std::panic::Location<'_>; + let mut _16: (); + let mut _17: u32; + let mut _18: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}; + let mut _19: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}; + let mut _20: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}; + let mut _21: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}; + let mut _22: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}; + let mut _23: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}; + let mut _24: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}; + let mut _25: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}; + + bb0: { + _18 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}); + _17 = discriminant((*_18)); + switchInt(move _17) -> [0: bb1, 1: bb19, 3: bb17, 4: bb18, otherwise: bb20]; + } + + bb1: { + _19 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}); + (((*_19) as variant#4).0: std::string::String) = move _2; + StorageLive(_3); + StorageLive(_4); + StorageLive(_5); + StorageLive(_6); + _20 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}); + _6 = &(((*_20) as variant#4).0: std::string::String); + _5 = <String as Clone>::clone(move _6) -> [return: bb2, unwind unreachable]; + } + + bb2: { + StorageDead(_6); + StorageLive(_7); + _7 = Location::<'_>::caller() -> [return: bb3, unwind unreachable]; + } + + bb3: { + _4 = (const "first", move _5, move _7); + StorageDead(_7); + goto -> bb4; + } + + bb4: { + StorageDead(_5); + _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Yielded(move _4); + StorageDead(_3); + StorageDead(_4); + _21 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}); + discriminant((*_21)) = 3; + return; + } + + bb5: { + goto -> bb6; + } + + bb6: { + StorageDead(_4); + drop(_3) -> [return: bb7, unwind unreachable]; + } + + bb7: { + StorageDead(_3); + StorageLive(_8); + StorageLive(_9); + StorageLive(_10); + StorageLive(_11); + _11 = const "second"; + _10 = &(*_11); + StorageLive(_12); + StorageLive(_13); + _22 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}); + _13 = &(((*_22) as variant#4).0: std::string::String); + _12 = <String as Clone>::clone(move _13) -> [return: bb8, unwind unreachable]; + } + + bb8: { + StorageDead(_13); + StorageLive(_14); + StorageLive(_15); + _15 = Location::<'_>::caller() -> [return: bb9, unwind unreachable]; + } + + bb9: { + _14 = &(*_15); + _9 = (move _10, move _12, move _14); + StorageDead(_14); + goto -> bb10; + } + + bb10: { + StorageDead(_12); + StorageDead(_10); + _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Yielded(move _9); + StorageDead(_8); + StorageDead(_9); + StorageDead(_11); + StorageDead(_15); + _23 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}); + discriminant((*_23)) = 4; + return; + } + + bb11: { + goto -> bb12; + } + + bb12: { + StorageDead(_9); + drop(_8) -> [return: bb13, unwind unreachable]; + } + + bb13: { + StorageDead(_15); + StorageDead(_11); + StorageDead(_8); + _16 = const (); + _24 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}); + drop((((*_24) as variant#4).0: std::string::String)) -> [return: bb14, unwind unreachable]; + } + + bb14: { + goto -> bb16; + } + + bb15: { + _0 = CoroutineState::<(&str, String, &Location<'_>), ()>::Complete(move _16); + _25 = deref_copy (_1.0: &mut {coroutine@$DIR/coroutine.rs:25:5: 25:18}); + discriminant((*_25)) = 1; + return; + } + + bb16: { + goto -> bb15; + } + + bb17: { + StorageLive(_3); + StorageLive(_4); + _3 = move _2; + goto -> bb5; + } + + bb18: { + StorageLive(_8); + StorageLive(_9); + StorageLive(_11); + StorageLive(_15); + _8 = move _2; + goto -> bb11; + } + + bb19: { + assert(const false, "coroutine resumed after completion") -> [success: bb19, unwind unreachable]; + } + + bb20: { + unreachable; + } +} + +ALLOC0 (size: 6, align: 1) { + 73 65 63 6f 6e 64 │ second +} + +ALLOC1 (size: 5, align: 1) { + 66 69 72 73 74 │ first +} diff --git a/tests/mir-opt/building/coroutine.rs b/tests/mir-opt/building/coroutine.rs new file mode 100644 index 00000000000..6d50c4d90b1 --- /dev/null +++ b/tests/mir-opt/building/coroutine.rs @@ -0,0 +1,29 @@ +// skip-filecheck +//@ edition:2024 +//@ compile-flags: -Zmir-opt-level=0 -C panic=abort + +#![feature(stmt_expr_attributes)] +#![feature(closure_track_caller)] +#![feature(coroutine_trait)] +#![feature(coroutines)] + +use std::ops::{Coroutine, CoroutineState}; +use std::panic::Location; +use std::pin::Pin; + +// EMIT_MIR coroutine.main-{closure#0}.StateTransform.after.mir +// EMIT_MIR coroutine.main-{closure#1}.StateTransform.after.mir +fn main() { + let simple = #[coroutine] + |arg: String| { + yield ("first", arg.clone(), Location::caller()); + yield ("second", arg.clone(), Location::caller()); + }; + + let track_caller = #[track_caller] + #[coroutine] + |arg: String| { + yield ("first", arg.clone(), Location::caller()); + yield ("second", arg.clone(), Location::caller()); + }; +} diff --git a/tests/mir-opt/building/custom/arrays.arrays.built.after.mir b/tests/mir-opt/building/custom/arrays.arrays.built.after.mir index 30d11e31e4d..f9f24c8eabe 100644 --- a/tests/mir-opt/building/custom/arrays.arrays.built.after.mir +++ b/tests/mir-opt/building/custom/arrays.arrays.built.after.mir @@ -3,12 +3,16 @@ fn arrays() -> usize { let mut _0: usize; let mut _1: [i32; C]; - let mut _2: usize; + let mut _2: *const [i32; C]; + let mut _3: *const [i32]; + let mut _4: usize; bb0: { _1 = [const 5_i32; C]; - _2 = Len(_1); - _0 = copy _2; + _2 = &raw const _1; + _3 = copy _2 as *const [i32] (PointerCoercion(Unsize, AsCast)); + _4 = PtrMetadata(copy _3); + _0 = copy _4; return; } } diff --git a/tests/mir-opt/building/custom/arrays.rs b/tests/mir-opt/building/custom/arrays.rs index 4bd6f93e113..e9cdded4a0e 100644 --- a/tests/mir-opt/building/custom/arrays.rs +++ b/tests/mir-opt/building/custom/arrays.rs @@ -10,7 +10,9 @@ fn arrays<const C: usize>() -> usize { mir! { { let x = [5_i32; C]; - let c = Len(x); + let y = &raw const x; + let z = CastUnsize::<_, *const [i32]>(y); + let c = PtrMetadata(z); RET = c; Return() } diff --git a/tests/mir-opt/building/match/array_len.const_array_len.built.after.panic-abort.mir b/tests/mir-opt/building/match/array_len.const_array_len.built.after.panic-abort.mir new file mode 100644 index 00000000000..8d16f074b1e --- /dev/null +++ b/tests/mir-opt/building/match/array_len.const_array_len.built.after.panic-abort.mir @@ -0,0 +1,155 @@ +// MIR for `const_array_len` after built + +fn const_array_len(_1: [T; 5]) -> () { + debug x => _1; + let mut _0: (); + let _6: (); + let mut _7: T; + let _8: (); + let mut _9: T; + let _10: (); + let mut _11: [T; 2]; + let _12: (); + let mut _13: T; + scope 1 { + debug a => _2; + debug b => _3; + debug rest => _4; + debug e => _5; + let _2: T; + let _3: T; + let _4: [T; 2]; + let _5: T; + } + + bb0: { + PlaceMention(_1); + falseEdge -> [real: bb2, imaginary: bb1]; + } + + bb1: { + goto -> bb7; + } + + bb2: { + StorageLive(_2); + _2 = move _1[0 of 5]; + StorageLive(_3); + _3 = move _1[1 of 5]; + StorageLive(_4); + _4 = move _1[2..4]; + StorageLive(_5); + _5 = move _1[4 of 5]; + StorageLive(_6); + StorageLive(_7); + _7 = move _2; + _6 = opaque::<T>(move _7) -> [return: bb3, unwind: bb17]; + } + + bb3: { + StorageDead(_7); + StorageDead(_6); + StorageLive(_8); + StorageLive(_9); + _9 = move _3; + _8 = opaque::<T>(move _9) -> [return: bb4, unwind: bb16]; + } + + bb4: { + StorageDead(_9); + StorageDead(_8); + StorageLive(_10); + StorageLive(_11); + _11 = move _4; + _10 = opaque::<[T; 2]>(move _11) -> [return: bb5, unwind: bb15]; + } + + bb5: { + StorageDead(_11); + StorageDead(_10); + StorageLive(_12); + StorageLive(_13); + _13 = move _5; + _12 = opaque::<T>(move _13) -> [return: bb6, unwind: bb14]; + } + + bb6: { + StorageDead(_13); + StorageDead(_12); + _0 = const (); + drop(_5) -> [return: bb8, unwind: bb19]; + } + + bb7: { + _0 = const (); + goto -> bb12; + } + + bb8: { + StorageDead(_5); + drop(_4) -> [return: bb9, unwind: bb20]; + } + + bb9: { + StorageDead(_4); + drop(_3) -> [return: bb10, unwind: bb21]; + } + + bb10: { + StorageDead(_3); + drop(_2) -> [return: bb11, unwind: bb22]; + } + + bb11: { + StorageDead(_2); + goto -> bb12; + } + + bb12: { + drop(_1) -> [return: bb13, unwind: bb23]; + } + + bb13: { + return; + } + + bb14 (cleanup): { + drop(_13) -> [return: bb18, unwind terminate(cleanup)]; + } + + bb15 (cleanup): { + drop(_11) -> [return: bb18, unwind terminate(cleanup)]; + } + + bb16 (cleanup): { + drop(_9) -> [return: bb18, unwind terminate(cleanup)]; + } + + bb17 (cleanup): { + drop(_7) -> [return: bb18, unwind terminate(cleanup)]; + } + + bb18 (cleanup): { + drop(_5) -> [return: bb19, unwind terminate(cleanup)]; + } + + bb19 (cleanup): { + drop(_4) -> [return: bb20, unwind terminate(cleanup)]; + } + + bb20 (cleanup): { + drop(_3) -> [return: bb21, unwind terminate(cleanup)]; + } + + bb21 (cleanup): { + drop(_2) -> [return: bb22, unwind terminate(cleanup)]; + } + + bb22 (cleanup): { + drop(_1) -> [return: bb23, unwind terminate(cleanup)]; + } + + bb23 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/match/array_len.const_array_len.built.after.panic-unwind.mir b/tests/mir-opt/building/match/array_len.const_array_len.built.after.panic-unwind.mir new file mode 100644 index 00000000000..8d16f074b1e --- /dev/null +++ b/tests/mir-opt/building/match/array_len.const_array_len.built.after.panic-unwind.mir @@ -0,0 +1,155 @@ +// MIR for `const_array_len` after built + +fn const_array_len(_1: [T; 5]) -> () { + debug x => _1; + let mut _0: (); + let _6: (); + let mut _7: T; + let _8: (); + let mut _9: T; + let _10: (); + let mut _11: [T; 2]; + let _12: (); + let mut _13: T; + scope 1 { + debug a => _2; + debug b => _3; + debug rest => _4; + debug e => _5; + let _2: T; + let _3: T; + let _4: [T; 2]; + let _5: T; + } + + bb0: { + PlaceMention(_1); + falseEdge -> [real: bb2, imaginary: bb1]; + } + + bb1: { + goto -> bb7; + } + + bb2: { + StorageLive(_2); + _2 = move _1[0 of 5]; + StorageLive(_3); + _3 = move _1[1 of 5]; + StorageLive(_4); + _4 = move _1[2..4]; + StorageLive(_5); + _5 = move _1[4 of 5]; + StorageLive(_6); + StorageLive(_7); + _7 = move _2; + _6 = opaque::<T>(move _7) -> [return: bb3, unwind: bb17]; + } + + bb3: { + StorageDead(_7); + StorageDead(_6); + StorageLive(_8); + StorageLive(_9); + _9 = move _3; + _8 = opaque::<T>(move _9) -> [return: bb4, unwind: bb16]; + } + + bb4: { + StorageDead(_9); + StorageDead(_8); + StorageLive(_10); + StorageLive(_11); + _11 = move _4; + _10 = opaque::<[T; 2]>(move _11) -> [return: bb5, unwind: bb15]; + } + + bb5: { + StorageDead(_11); + StorageDead(_10); + StorageLive(_12); + StorageLive(_13); + _13 = move _5; + _12 = opaque::<T>(move _13) -> [return: bb6, unwind: bb14]; + } + + bb6: { + StorageDead(_13); + StorageDead(_12); + _0 = const (); + drop(_5) -> [return: bb8, unwind: bb19]; + } + + bb7: { + _0 = const (); + goto -> bb12; + } + + bb8: { + StorageDead(_5); + drop(_4) -> [return: bb9, unwind: bb20]; + } + + bb9: { + StorageDead(_4); + drop(_3) -> [return: bb10, unwind: bb21]; + } + + bb10: { + StorageDead(_3); + drop(_2) -> [return: bb11, unwind: bb22]; + } + + bb11: { + StorageDead(_2); + goto -> bb12; + } + + bb12: { + drop(_1) -> [return: bb13, unwind: bb23]; + } + + bb13: { + return; + } + + bb14 (cleanup): { + drop(_13) -> [return: bb18, unwind terminate(cleanup)]; + } + + bb15 (cleanup): { + drop(_11) -> [return: bb18, unwind terminate(cleanup)]; + } + + bb16 (cleanup): { + drop(_9) -> [return: bb18, unwind terminate(cleanup)]; + } + + bb17 (cleanup): { + drop(_7) -> [return: bb18, unwind terminate(cleanup)]; + } + + bb18 (cleanup): { + drop(_5) -> [return: bb19, unwind terminate(cleanup)]; + } + + bb19 (cleanup): { + drop(_4) -> [return: bb20, unwind terminate(cleanup)]; + } + + bb20 (cleanup): { + drop(_3) -> [return: bb21, unwind terminate(cleanup)]; + } + + bb21 (cleanup): { + drop(_2) -> [return: bb22, unwind terminate(cleanup)]; + } + + bb22 (cleanup): { + drop(_1) -> [return: bb23, unwind terminate(cleanup)]; + } + + bb23 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/match/array_len.rs b/tests/mir-opt/building/match/array_len.rs new file mode 100644 index 00000000000..0d889ada9b6 --- /dev/null +++ b/tests/mir-opt/building/match/array_len.rs @@ -0,0 +1,31 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ compile-flags: -Zmir-opt-level=0 + +fn opaque<T>(x: T) {} + +// EMIT_MIR array_len.const_array_len.built.after.mir +fn const_array_len<T>(x: [T; 5]) { + // CHECK-LABEL: fn const_array_len( + // CHECK-NOT: Len + // CHECK-NOT: PtrMetadata + // CHECK: = const 5_usize; + if let [a, b, rest @ .., e] = x { + opaque(a); + opaque(b); + opaque(rest); + opaque(e); + } +} + +// EMIT_MIR array_len.slice_len.built.after.mir +fn slice_len<T>(x: &[T]) { + // CHECK-LABEL: fn slice_len( + // CHECK-NOT: Len + // CHECK: = PtrMetadata(copy _1); + if let [a, b, rest @ .., e] = x { + opaque(a); + opaque(b); + opaque(rest); + opaque(e); + } +} diff --git a/tests/mir-opt/building/match/array_len.slice_len.built.after.panic-abort.mir b/tests/mir-opt/building/match/array_len.slice_len.built.after.panic-abort.mir new file mode 100644 index 00000000000..d73f5a1b6f7 --- /dev/null +++ b/tests/mir-opt/building/match/array_len.slice_len.built.after.panic-abort.mir @@ -0,0 +1,115 @@ +// MIR for `slice_len` after built + +fn slice_len(_1: &[T]) -> () { + debug x => _1; + let mut _0: (); + let mut _2: usize; + let mut _3: usize; + let mut _4: usize; + let mut _5: bool; + let _10: (); + let mut _11: &T; + let _12: (); + let mut _13: &T; + let _14: (); + let mut _15: &[T]; + let _16: (); + let mut _17: &T; + scope 1 { + debug a => _6; + debug b => _7; + debug rest => _8; + debug e => _9; + let _6: &T; + let _7: &T; + let _8: &[T]; + let _9: &T; + } + + bb0: { + PlaceMention(_1); + _3 = PtrMetadata(copy _1); + _2 = move _3; + _4 = const 3_usize; + _5 = Ge(move _2, move _4); + switchInt(move _5) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + goto -> bb9; + } + + bb2: { + falseEdge -> [real: bb4, imaginary: bb1]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + StorageLive(_6); + _6 = &(*_1)[0 of 3]; + StorageLive(_7); + _7 = &(*_1)[1 of 3]; + StorageLive(_8); + _8 = &(*_1)[2:-1]; + StorageLive(_9); + _9 = &(*_1)[-1 of 3]; + StorageLive(_10); + StorageLive(_11); + _11 = copy _6; + _10 = opaque::<&T>(move _11) -> [return: bb5, unwind: bb11]; + } + + bb5: { + StorageDead(_11); + StorageDead(_10); + StorageLive(_12); + StorageLive(_13); + _13 = copy _7; + _12 = opaque::<&T>(move _13) -> [return: bb6, unwind: bb11]; + } + + bb6: { + StorageDead(_13); + StorageDead(_12); + StorageLive(_14); + StorageLive(_15); + _15 = copy _8; + _14 = opaque::<&[T]>(move _15) -> [return: bb7, unwind: bb11]; + } + + bb7: { + StorageDead(_15); + StorageDead(_14); + StorageLive(_16); + StorageLive(_17); + _17 = copy _9; + _16 = opaque::<&T>(move _17) -> [return: bb8, unwind: bb11]; + } + + bb8: { + StorageDead(_17); + StorageDead(_16); + _0 = const (); + StorageDead(_9); + StorageDead(_8); + StorageDead(_7); + StorageDead(_6); + goto -> bb10; + } + + bb9: { + _0 = const (); + goto -> bb10; + } + + bb10: { + return; + } + + bb11 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/building/match/array_len.slice_len.built.after.panic-unwind.mir b/tests/mir-opt/building/match/array_len.slice_len.built.after.panic-unwind.mir new file mode 100644 index 00000000000..d73f5a1b6f7 --- /dev/null +++ b/tests/mir-opt/building/match/array_len.slice_len.built.after.panic-unwind.mir @@ -0,0 +1,115 @@ +// MIR for `slice_len` after built + +fn slice_len(_1: &[T]) -> () { + debug x => _1; + let mut _0: (); + let mut _2: usize; + let mut _3: usize; + let mut _4: usize; + let mut _5: bool; + let _10: (); + let mut _11: &T; + let _12: (); + let mut _13: &T; + let _14: (); + let mut _15: &[T]; + let _16: (); + let mut _17: &T; + scope 1 { + debug a => _6; + debug b => _7; + debug rest => _8; + debug e => _9; + let _6: &T; + let _7: &T; + let _8: &[T]; + let _9: &T; + } + + bb0: { + PlaceMention(_1); + _3 = PtrMetadata(copy _1); + _2 = move _3; + _4 = const 3_usize; + _5 = Ge(move _2, move _4); + switchInt(move _5) -> [0: bb1, otherwise: bb2]; + } + + bb1: { + goto -> bb9; + } + + bb2: { + falseEdge -> [real: bb4, imaginary: bb1]; + } + + bb3: { + goto -> bb1; + } + + bb4: { + StorageLive(_6); + _6 = &(*_1)[0 of 3]; + StorageLive(_7); + _7 = &(*_1)[1 of 3]; + StorageLive(_8); + _8 = &(*_1)[2:-1]; + StorageLive(_9); + _9 = &(*_1)[-1 of 3]; + StorageLive(_10); + StorageLive(_11); + _11 = copy _6; + _10 = opaque::<&T>(move _11) -> [return: bb5, unwind: bb11]; + } + + bb5: { + StorageDead(_11); + StorageDead(_10); + StorageLive(_12); + StorageLive(_13); + _13 = copy _7; + _12 = opaque::<&T>(move _13) -> [return: bb6, unwind: bb11]; + } + + bb6: { + StorageDead(_13); + StorageDead(_12); + StorageLive(_14); + StorageLive(_15); + _15 = copy _8; + _14 = opaque::<&[T]>(move _15) -> [return: bb7, unwind: bb11]; + } + + bb7: { + StorageDead(_15); + StorageDead(_14); + StorageLive(_16); + StorageLive(_17); + _17 = copy _9; + _16 = opaque::<&T>(move _17) -> [return: bb8, unwind: bb11]; + } + + bb8: { + StorageDead(_17); + StorageDead(_16); + _0 = const (); + StorageDead(_9); + StorageDead(_8); + StorageDead(_7); + StorageDead(_6); + goto -> bb10; + } + + bb9: { + _0 = const (); + goto -> bb10; + } + + bb10: { + return; + } + + bb11 (cleanup): { + resume; + } +} diff --git a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir index 7e033916fd3..33fbca7f77e 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir +++ b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-abort.mir @@ -7,15 +7,14 @@ fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:12:5: 12 let _4: (); let mut _5: (); let mut _6: (); - let mut _7: (); - let mut _8: u32; + let mut _7: u32; scope 1 { debug _s => (((*_1) as variant#3).0: std::string::String); } bb0: { - _8 = discriminant((*_1)); - switchInt(move _8) -> [0: bb5, 3: bb8, otherwise: bb9]; + _7 = discriminant((*_1)); + switchInt(move _7) -> [0: bb5, 3: bb8, otherwise: bb9]; } bb1: { diff --git a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir index 613ef2909b5..69e7219af9f 100644 --- a/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir +++ b/tests/mir-opt/coroutine_drop_cleanup.main-{closure#0}.coroutine_drop.0.panic-unwind.mir @@ -7,15 +7,14 @@ fn main::{closure#0}(_1: *mut {coroutine@$DIR/coroutine_drop_cleanup.rs:12:5: 12 let _4: (); let mut _5: (); let mut _6: (); - let mut _7: (); - let mut _8: u32; + let mut _7: u32; scope 1 { debug _s => (((*_1) as variant#3).0: std::string::String); } bb0: { - _8 = discriminant((*_1)); - switchInt(move _8) -> [0: bb7, 3: bb10, otherwise: bb11]; + _7 = discriminant((*_1)); + switchInt(move _7) -> [0: bb7, 3: bb10, otherwise: bb11]; } bb1: { diff --git a/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir b/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir index f8b3f68d21e..9905cc3e00f 100644 --- a/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir +++ b/tests/mir-opt/coroutine_tiny.main-{closure#0}.coroutine_resume.0.mir @@ -1,7 +1,7 @@ // MIR for `main::{closure#0}` 0 coroutine_resume /* coroutine_layout = CoroutineLayout { field_tys: { - _0: CoroutineSavedTy { + _s0: CoroutineSavedTy { ty: HasDrop, source_info: SourceInfo { span: $DIR/coroutine_tiny.rs:22:13: 22:15 (#0), @@ -14,15 +14,15 @@ Unresumed(0): [], Returned (1): [], Panicked (2): [], - Suspend0 (3): [_0], + Suspend0 (3): [_s0], }, storage_conflicts: BitMatrix(1x1) { - (_0, _0), + (_s0, _s0), }, } */ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}>, _2: u8) -> CoroutineState<(), ()> { - debug _x => _10; + debug _x => _2; let mut _0: std::ops::CoroutineState<(), ()>; let _3: HasDrop; let mut _4: !; @@ -31,19 +31,17 @@ fn main::{closure#0}(_1: Pin<&mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13} let mut _7: (); let _8: (); let mut _9: (); - let _10: u8; - let mut _11: u32; + let mut _10: u32; scope 1 { debug _d => (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})) as variant#3).0: HasDrop); } bb0: { - _11 = discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}))); - switchInt(move _11) -> [0: bb1, 3: bb5, otherwise: bb6]; + _10 = discriminant((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13}))); + switchInt(move _10) -> [0: bb1, 3: bb5, otherwise: bb6]; } bb1: { - _10 = move _2; nop; (((*(_1.0: &mut {coroutine@$DIR/coroutine_tiny.rs:21:5: 21:13})) as variant#3).0: HasDrop) = HasDrop; StorageLive(_4); diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff new file mode 100644 index 00000000000..fd9ef54fe77 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-abort.diff @@ -0,0 +1,77 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _14 = const main::promoted[0]; + _4 = copy _14; + _3 = copy _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = PtrMetadata(copy _2); +- _8 = Lt(copy _6, copy _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _1 = copy (*_2)[_6]; ++ _1 = copy (*_2)[1 of 2]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageLive(_9); + StorageLive(_10); + _10 = const main::SLICE; + StorageLive(_11); + _11 = const 1_usize; +- _12 = PtrMetadata(copy _10); +- _13 = Lt(copy _11, copy _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind unreachable]; ++ _12 = const 3_usize; ++ _13 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable]; + } + + bb2: { +- _9 = copy (*_10)[_11]; ++ _9 = copy (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff new file mode 100644 index 00000000000..1fec08c2562 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.32bit.panic-unwind.diff @@ -0,0 +1,77 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _14 = const main::promoted[0]; + _4 = copy _14; + _3 = copy _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = PtrMetadata(copy _2); +- _8 = Lt(copy _6, copy _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _1 = copy (*_2)[_6]; ++ _1 = copy (*_2)[1 of 2]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageLive(_9); + StorageLive(_10); + _10 = const main::SLICE; + StorageLive(_11); + _11 = const 1_usize; +- _12 = PtrMetadata(copy _10); +- _13 = Lt(copy _11, copy _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind continue]; ++ _12 = const 3_usize; ++ _13 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue]; + } + + bb2: { +- _9 = copy (*_10)[_11]; ++ _9 = copy (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff new file mode 100644 index 00000000000..fd9ef54fe77 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-abort.diff @@ -0,0 +1,77 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _14 = const main::promoted[0]; + _4 = copy _14; + _3 = copy _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = PtrMetadata(copy _2); +- _8 = Lt(copy _6, copy _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind unreachable]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind unreachable]; + } + + bb1: { +- _1 = copy (*_2)[_6]; ++ _1 = copy (*_2)[1 of 2]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageLive(_9); + StorageLive(_10); + _10 = const main::SLICE; + StorageLive(_11); + _11 = const 1_usize; +- _12 = PtrMetadata(copy _10); +- _13 = Lt(copy _11, copy _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind unreachable]; ++ _12 = const 3_usize; ++ _13 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind unreachable]; + } + + bb2: { +- _9 = copy (*_10)[_11]; ++ _9 = copy (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff new file mode 100644 index 00000000000..1fec08c2562 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.main.DataflowConstProp.64bit.panic-unwind.diff @@ -0,0 +1,77 @@ +- // MIR for `main` before DataflowConstProp ++ // MIR for `main` after DataflowConstProp + + fn main() -> () { + let mut _0: (); + let _1: u32; + let mut _2: &[u32]; + let mut _3: &[u32; 3]; + let _4: &[u32; 3]; + let _5: [u32; 3]; + let _6: usize; + let mut _7: usize; + let mut _8: bool; + let mut _10: &[u32]; + let _11: usize; + let mut _12: usize; + let mut _13: bool; + let mut _14: &[u32; 3]; + scope 1 { + debug local => _1; + let _9: u32; + scope 2 { + debug constant => _9; + } + } + + bb0: { + StorageLive(_1); + StorageLive(_2); + StorageLive(_3); + StorageLive(_4); + _14 = const main::promoted[0]; + _4 = copy _14; + _3 = copy _4; + _2 = move _3 as &[u32] (PointerCoercion(Unsize, AsCast)); + StorageDead(_3); + StorageLive(_6); + _6 = const 1_usize; +- _7 = PtrMetadata(copy _2); +- _8 = Lt(copy _6, copy _7); +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, copy _6) -> [success: bb1, unwind continue]; ++ _7 = const 3_usize; ++ _8 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb1, unwind continue]; + } + + bb1: { +- _1 = copy (*_2)[_6]; ++ _1 = copy (*_2)[1 of 2]; + StorageDead(_6); + StorageDead(_4); + StorageDead(_2); + StorageLive(_9); + StorageLive(_10); + _10 = const main::SLICE; + StorageLive(_11); + _11 = const 1_usize; +- _12 = PtrMetadata(copy _10); +- _13 = Lt(copy _11, copy _12); +- assert(move _13, "index out of bounds: the length is {} but the index is {}", move _12, copy _11) -> [success: bb2, unwind continue]; ++ _12 = const 3_usize; ++ _13 = const true; ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 3_usize, const 1_usize) -> [success: bb2, unwind continue]; + } + + bb2: { +- _9 = copy (*_10)[_11]; ++ _9 = copy (*_10)[1 of 2]; + StorageDead(_11); + StorageDead(_10); + _0 = const (); + StorageDead(_9); + StorageDead(_1); + return; + } + } + diff --git a/tests/mir-opt/dataflow-const-prop/slice_len.rs b/tests/mir-opt/dataflow-const-prop/slice_len.rs new file mode 100644 index 00000000000..e0e68f9fde5 --- /dev/null +++ b/tests/mir-opt/dataflow-const-prop/slice_len.rs @@ -0,0 +1,34 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ test-mir-pass: DataflowConstProp +//@ compile-flags: -Zmir-enable-passes=+InstSimplify-after-simplifycfg +// EMIT_MIR_FOR_EACH_BIT_WIDTH + +// EMIT_MIR slice_len.main.DataflowConstProp.diff + +// CHECK-LABEL: fn main( +fn main() { + // CHECK: debug local => [[local:_.*]]; + // CHECK: debug constant => [[constant:_.*]]; + + // CHECK-NOT: {{_.*}} = Len( + // CHECK-NOT: {{_.*}} = Lt( + // CHECK-NOT: assert(move _ + // CHECK: {{_.*}} = const 3_usize; + // CHECK: {{_.*}} = const true; + // CHECK: assert(const true, + + // CHECK: [[local]] = copy (*{{_.*}})[1 of 2]; + let local = (&[1u32, 2, 3] as &[u32])[1]; + + // CHECK-NOT: {{_.*}} = Len( + // CHECK-NOT: {{_.*}} = Lt( + // CHECK-NOT: assert(move _ + const SLICE: &[u32] = &[1, 2, 3]; + // CHECK: {{_.*}} = const 3_usize; + // CHECK: {{_.*}} = const true; + // CHECK: assert(const true, + + // CHECK-NOT: [[constant]] = {{copy|move}} (*{{_.*}})[_ + // CHECK: [[constant]] = copy (*{{_.*}})[1 of 2]; + let constant = SLICE[1]; +} diff --git a/tests/mir-opt/dest-prop/aggregate.rewrap.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/aggregate.rewrap.DestinationPropagation.panic-abort.diff new file mode 100644 index 00000000000..e80660f176b --- /dev/null +++ b/tests/mir-opt/dest-prop/aggregate.rewrap.DestinationPropagation.panic-abort.diff @@ -0,0 +1,19 @@ +- // MIR for `rewrap` before DestinationPropagation ++ // MIR for `rewrap` after DestinationPropagation + + fn rewrap() -> (u8,) { + let mut _0: (u8,); + let mut _1: (u8,); + let mut _2: (u8,); + + bb0: { +- (_1.0: u8) = const 0_u8; +- _0 = copy _1; ++ (_0.0: u8) = const 0_u8; ++ nop; + _2 = (copy (_0.0: u8),); + _0 = copy _2; + return; + } + } + diff --git a/tests/mir-opt/dest-prop/aggregate.rewrap.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/aggregate.rewrap.DestinationPropagation.panic-unwind.diff new file mode 100644 index 00000000000..e80660f176b --- /dev/null +++ b/tests/mir-opt/dest-prop/aggregate.rewrap.DestinationPropagation.panic-unwind.diff @@ -0,0 +1,19 @@ +- // MIR for `rewrap` before DestinationPropagation ++ // MIR for `rewrap` after DestinationPropagation + + fn rewrap() -> (u8,) { + let mut _0: (u8,); + let mut _1: (u8,); + let mut _2: (u8,); + + bb0: { +- (_1.0: u8) = const 0_u8; +- _0 = copy _1; ++ (_0.0: u8) = const 0_u8; ++ nop; + _2 = (copy (_0.0: u8),); + _0 = copy _2; + return; + } + } + diff --git a/tests/mir-opt/dest-prop/aggregate.rs b/tests/mir-opt/dest-prop/aggregate.rs new file mode 100644 index 00000000000..636852159eb --- /dev/null +++ b/tests/mir-opt/dest-prop/aggregate.rs @@ -0,0 +1,51 @@ +//@ test-mir-pass: DestinationPropagation +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY + +#![feature(custom_mir, core_intrinsics)] +#![allow(internal_features)] + +use std::intrinsics::mir::*; +use std::mem::MaybeUninit; + +fn dump_var<T>(_: T) {} + +// EMIT_MIR aggregate.rewrap.DestinationPropagation.diff +#[custom_mir(dialect = "runtime")] +fn rewrap() -> (u8,) { + // CHECK-LABEL: fn rewrap( + // CHECK: (_0.0: u8) = const 0_u8; + // CHECK: _2 = (copy (_0.0: u8),); + // CHECK: _0 = copy _2; + mir! { + let _1: (u8,); + let _2: (u8,); + { + _1.0 = 0; + RET = _1; + _2 = (RET.0, ); + RET = _2; + Return() + } + } +} + +// EMIT_MIR aggregate.swap.DestinationPropagation.diff +#[custom_mir(dialect = "runtime")] +fn swap() -> (MaybeUninit<[u8; 10]>, MaybeUninit<[u8; 10]>) { + // CHECK-LABEL: fn swap( + // CHECK: _0 = const + // CHECK: _2 = copy _0; + // CHECK: _0 = (copy (_2.1: {{.*}}), copy (_2.0: {{.*}})); + mir! { + let _1: (MaybeUninit<[u8; 10]>, MaybeUninit<[u8; 10]>); + let _2: (MaybeUninit<[u8; 10]>, MaybeUninit<[u8; 10]>); + let _3: (); + { + _1 = const { (MaybeUninit::new([0; 10]), MaybeUninit::new([1; 10])) }; + _2 = _1; + _1 = (_2.1, _2.0); + RET = _1; + Return() + } + } +} diff --git a/tests/mir-opt/dest-prop/aggregate.swap.DestinationPropagation.panic-abort.diff b/tests/mir-opt/dest-prop/aggregate.swap.DestinationPropagation.panic-abort.diff new file mode 100644 index 00000000000..3aaad3aaf69 --- /dev/null +++ b/tests/mir-opt/dest-prop/aggregate.swap.DestinationPropagation.panic-abort.diff @@ -0,0 +1,22 @@ +- // MIR for `swap` before DestinationPropagation ++ // MIR for `swap` after DestinationPropagation + + fn swap() -> (MaybeUninit<[u8; 10]>, MaybeUninit<[u8; 10]>) { + let mut _0: (std::mem::MaybeUninit<[u8; 10]>, std::mem::MaybeUninit<[u8; 10]>); + let mut _1: (std::mem::MaybeUninit<[u8; 10]>, std::mem::MaybeUninit<[u8; 10]>); + let mut _2: (std::mem::MaybeUninit<[u8; 10]>, std::mem::MaybeUninit<[u8; 10]>); + let mut _3: (); + + bb0: { +- _1 = const swap::{constant#6}; +- _2 = copy _1; +- _1 = (copy (_2.1: std::mem::MaybeUninit<[u8; 10]>), copy (_2.0: std::mem::MaybeUninit<[u8; 10]>)); +- _0 = copy _1; ++ _0 = const swap::{constant#6}; ++ _2 = copy _0; ++ _0 = (copy (_2.1: std::mem::MaybeUninit<[u8; 10]>), copy (_2.0: std::mem::MaybeUninit<[u8; 10]>)); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/dest-prop/aggregate.swap.DestinationPropagation.panic-unwind.diff b/tests/mir-opt/dest-prop/aggregate.swap.DestinationPropagation.panic-unwind.diff new file mode 100644 index 00000000000..3aaad3aaf69 --- /dev/null +++ b/tests/mir-opt/dest-prop/aggregate.swap.DestinationPropagation.panic-unwind.diff @@ -0,0 +1,22 @@ +- // MIR for `swap` before DestinationPropagation ++ // MIR for `swap` after DestinationPropagation + + fn swap() -> (MaybeUninit<[u8; 10]>, MaybeUninit<[u8; 10]>) { + let mut _0: (std::mem::MaybeUninit<[u8; 10]>, std::mem::MaybeUninit<[u8; 10]>); + let mut _1: (std::mem::MaybeUninit<[u8; 10]>, std::mem::MaybeUninit<[u8; 10]>); + let mut _2: (std::mem::MaybeUninit<[u8; 10]>, std::mem::MaybeUninit<[u8; 10]>); + let mut _3: (); + + bb0: { +- _1 = const swap::{constant#6}; +- _2 = copy _1; +- _1 = (copy (_2.1: std::mem::MaybeUninit<[u8; 10]>), copy (_2.0: std::mem::MaybeUninit<[u8; 10]>)); +- _0 = copy _1; ++ _0 = const swap::{constant#6}; ++ _2 = copy _0; ++ _0 = (copy (_2.1: std::mem::MaybeUninit<[u8; 10]>), copy (_2.0: std::mem::MaybeUninit<[u8; 10]>)); ++ nop; + return; + } + } + diff --git a/tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-abort.diff b/tests/mir-opt/dest-prop/nrvo_borrowed.nrvo.DestinationPropagation.panic-abort.diff index 6dce3ec5303..e9fbcf20a72 100644 --- a/tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-abort.diff +++ b/tests/mir-opt/dest-prop/nrvo_borrowed.nrvo.DestinationPropagation.panic-abort.diff @@ -1,5 +1,5 @@ -- // MIR for `nrvo` before RenameReturnPlace -+ // MIR for `nrvo` after RenameReturnPlace +- // MIR for `nrvo` before DestinationPropagation ++ // MIR for `nrvo` after DestinationPropagation fn nrvo(_1: for<'a> fn(&'a mut [u8; 1024])) -> [u8; 1024] { debug init => _1; @@ -10,32 +10,33 @@ let mut _5: &mut [u8; 1024]; let mut _6: &mut [u8; 1024]; scope 1 { -- debug buf => _2; -+ debug buf => _0; + debug buf => _2; } bb0: { -- StorageLive(_2); -- _2 = [const 0_u8; 1024]; -+ _0 = [const 0_u8; 1024]; + StorageLive(_2); + _2 = [const 0_u8; 1024]; StorageLive(_3); - StorageLive(_4); - _4 = copy _1; +- StorageLive(_4); +- _4 = copy _1; ++ nop; ++ nop; StorageLive(_5); StorageLive(_6); -- _6 = &mut _2; -+ _6 = &mut _0; + _6 = &mut _2; _5 = &mut (*_6); - _3 = move _4(move _5) -> [return: bb1, unwind unreachable]; +- _3 = move _4(move _5) -> [return: bb1, unwind unreachable]; ++ _3 = move _1(move _5) -> [return: bb1, unwind unreachable]; } bb1: { StorageDead(_5); - StorageDead(_4); +- StorageDead(_4); ++ nop; StorageDead(_6); StorageDead(_3); -- _0 = copy _2; -- StorageDead(_2); + _0 = copy _2; + StorageDead(_2); return; } } diff --git a/tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-unwind.diff b/tests/mir-opt/dest-prop/nrvo_borrowed.nrvo.DestinationPropagation.panic-unwind.diff index 54cbe2871f1..95d5fe1b930 100644 --- a/tests/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.panic-unwind.diff +++ b/tests/mir-opt/dest-prop/nrvo_borrowed.nrvo.DestinationPropagation.panic-unwind.diff @@ -1,5 +1,5 @@ -- // MIR for `nrvo` before RenameReturnPlace -+ // MIR for `nrvo` after RenameReturnPlace +- // MIR for `nrvo` before DestinationPropagation ++ // MIR for `nrvo` after DestinationPropagation fn nrvo(_1: for<'a> fn(&'a mut [u8; 1024])) -> [u8; 1024] { debug init => _1; @@ -10,32 +10,33 @@ let mut _5: &mut [u8; 1024]; let mut _6: &mut [u8; 1024]; scope 1 { -- debug buf => _2; -+ debug buf => _0; + debug buf => _2; } bb0: { -- StorageLive(_2); -- _2 = [const 0_u8; 1024]; -+ _0 = [const 0_u8; 1024]; + StorageLive(_2); + _2 = [const 0_u8; 1024]; StorageLive(_3); - StorageLive(_4); - _4 = copy _1; +- StorageLive(_4); +- _4 = copy _1; ++ nop; ++ nop; StorageLive(_5); StorageLive(_6); -- _6 = &mut _2; -+ _6 = &mut _0; + _6 = &mut _2; _5 = &mut (*_6); - _3 = move _4(move _5) -> [return: bb1, unwind continue]; +- _3 = move _4(move _5) -> [return: bb1, unwind continue]; ++ _3 = move _1(move _5) -> [return: bb1, unwind continue]; } bb1: { StorageDead(_5); - StorageDead(_4); +- StorageDead(_4); ++ nop; StorageDead(_6); StorageDead(_3); -- _0 = copy _2; -- StorageDead(_2); + _0 = copy _2; + StorageDead(_2); return; } } diff --git a/tests/mir-opt/nrvo_simple.rs b/tests/mir-opt/dest-prop/nrvo_borrowed.rs index df540472e1c..6f3076d4c13 100644 --- a/tests/mir-opt/nrvo_simple.rs +++ b/tests/mir-opt/dest-prop/nrvo_borrowed.rs @@ -1,8 +1,8 @@ // skip-filecheck // EMIT_MIR_FOR_EACH_PANIC_STRATEGY -//@ test-mir-pass: RenameReturnPlace +//@ test-mir-pass: DestinationPropagation -// EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff +// EMIT_MIR nrvo_borrowed.nrvo.DestinationPropagation.diff fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { let mut buf = [0; 1024]; init(&mut buf); diff --git a/tests/mir-opt/nrvo_miscompile_111005.rs b/tests/mir-opt/dest-prop/nrvo_miscompile_111005.rs index 131f7b8f6f9..17e6450278a 100644 --- a/tests/mir-opt/nrvo_miscompile_111005.rs +++ b/tests/mir-opt/dest-prop/nrvo_miscompile_111005.rs @@ -1,18 +1,17 @@ // This is a miscompilation, #111005 to track -//@ test-mir-pass: RenameReturnPlace +//@ test-mir-pass: DestinationPropagation #![feature(custom_mir, core_intrinsics)] extern crate core; use core::intrinsics::mir::*; -// EMIT_MIR nrvo_miscompile_111005.wrong.RenameReturnPlace.diff +// EMIT_MIR nrvo_miscompile_111005.wrong.DestinationPropagation.diff #[custom_mir(dialect = "runtime", phase = "initial")] pub fn wrong(arg: char) -> char { // CHECK-LABEL: fn wrong( // CHECK: _0 = copy _1; - // FIXME: This is wrong: - // CHECK-NEXT: _0 = const 'b'; + // CHECK-NEXT: _1 = const 'b'; // CHECK-NEXT: return; mir! { { diff --git a/tests/mir-opt/nrvo_miscompile_111005.wrong.RenameReturnPlace.diff b/tests/mir-opt/dest-prop/nrvo_miscompile_111005.wrong.DestinationPropagation.diff index d248c76f261..60cf9236f6c 100644 --- a/tests/mir-opt/nrvo_miscompile_111005.wrong.RenameReturnPlace.diff +++ b/tests/mir-opt/dest-prop/nrvo_miscompile_111005.wrong.DestinationPropagation.diff @@ -1,5 +1,5 @@ -- // MIR for `wrong` before RenameReturnPlace -+ // MIR for `wrong` after RenameReturnPlace +- // MIR for `wrong` before DestinationPropagation ++ // MIR for `wrong` after DestinationPropagation fn wrong(_1: char) -> char { let mut _0: char; @@ -9,8 +9,9 @@ - _2 = copy _1; - _0 = copy _2; - _2 = const 'b'; ++ nop; + _0 = copy _1; -+ _0 = const 'b'; ++ _1 = const 'b'; return; } } diff --git a/tests/mir-opt/gvn.array_len.GVN.panic-abort.diff b/tests/mir-opt/gvn.array_len.GVN.panic-abort.diff index 0d0477fe772..59b65a52f4e 100644 --- a/tests/mir-opt/gvn.array_len.GVN.panic-abort.diff +++ b/tests/mir-opt/gvn.array_len.GVN.panic-abort.diff @@ -12,8 +12,7 @@ } bb0: { -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); _3 = &(*_1); _2 = move _3 as &[i32] (PointerCoercion(Unsize, Implicit)); @@ -23,8 +22,7 @@ - _0 = PtrMetadata(move _4); + _0 = const 42_usize; StorageDead(_4); -- StorageDead(_2); -+ nop; + StorageDead(_2); return; } } diff --git a/tests/mir-opt/gvn.array_len.GVN.panic-unwind.diff b/tests/mir-opt/gvn.array_len.GVN.panic-unwind.diff index 0d0477fe772..59b65a52f4e 100644 --- a/tests/mir-opt/gvn.array_len.GVN.panic-unwind.diff +++ b/tests/mir-opt/gvn.array_len.GVN.panic-unwind.diff @@ -12,8 +12,7 @@ } bb0: { -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); _3 = &(*_1); _2 = move _3 as &[i32] (PointerCoercion(Unsize, Implicit)); @@ -23,8 +22,7 @@ - _0 = PtrMetadata(move _4); + _0 = const 42_usize; StorageDead(_4); -- StorageDead(_2); -+ nop; + StorageDead(_2); return; } } diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff index 22e6ea722dd..2ae86e2eb8b 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-abort.diff @@ -39,8 +39,8 @@ + let mut _28: &mut std::task::Context<'_>; + let mut _29: (); + let mut _30: (); -+ let mut _31: &mut std::task::Context<'_>; -+ let mut _32: u32; ++ let mut _31: u32; ++ let mut _32: &mut {async fn body of ActionPermit<'_, T>::perform()}; + let mut _33: &mut {async fn body of ActionPermit<'_, T>::perform()}; + let mut _34: &mut {async fn body of ActionPermit<'_, T>::perform()}; + let mut _35: &mut {async fn body of ActionPermit<'_, T>::perform()}; @@ -48,7 +48,6 @@ + let mut _37: &mut {async fn body of ActionPermit<'_, T>::perform()}; + let mut _38: &mut {async fn body of ActionPermit<'_, T>::perform()}; + let mut _39: &mut {async fn body of ActionPermit<'_, T>::perform()}; -+ let mut _40: &mut {async fn body of ActionPermit<'_, T>::perform()}; + scope 7 { + let mut _15: std::future::Ready<()>; + scope 8 { @@ -58,14 +57,14 @@ + scope 12 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } + scope 13 (inlined <std::future::Ready<()> as Future>::poll) { -+ let mut _42: (); -+ let mut _43: std::option::Option<()>; -+ let mut _44: &mut std::option::Option<()>; -+ let mut _45: &mut std::future::Ready<()>; -+ let mut _46: &mut std::pin::Pin<&mut std::future::Ready<()>>; ++ let mut _41: (); ++ let mut _42: std::option::Option<()>; ++ let mut _43: &mut std::option::Option<()>; ++ let mut _44: &mut std::future::Ready<()>; ++ let mut _45: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) { + scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) { -+ let mut _47: &mut &mut std::future::Ready<()>; ++ let mut _46: &mut &mut std::future::Ready<()>; + scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } + scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { @@ -75,22 +74,22 @@ + } + } + scope 19 (inlined Option::<()>::take) { -+ let mut _48: std::option::Option<()>; ++ let mut _47: std::option::Option<()>; + scope 20 (inlined std::mem::replace::<Option<()>>) { + scope 21 { + } + } + } + scope 22 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _49: isize; -+ let mut _50: !; ++ let mut _48: isize; ++ let mut _49: !; + scope 23 { + } + } + } + } + scope 10 (inlined ready::<()>) { -+ let mut _41: std::option::Option<()>; ++ let mut _40: std::option::Option<()>; + } + scope 11 (inlined <std::future::Ready<()> as IntoFuture>::into_future) { + } @@ -145,10 +144,9 @@ + StorageLive(_37); + StorageLive(_38); + StorageLive(_39); -+ StorageLive(_40); -+ _33 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ _32 = discriminant((*_33)); -+ switchInt(move _32) -> [0: bb3, 1: bb10, 3: bb9, otherwise: bb5]; ++ _32 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ _31 = discriminant((*_32)); ++ switchInt(move _31) -> [0: bb3, 1: bb10, 3: bb9, otherwise: bb5]; } - bb3: { @@ -158,7 +156,6 @@ + } + + bb2: { -+ StorageDead(_40); + StorageDead(_39); + StorageDead(_38); + StorageDead(_37); @@ -186,23 +183,22 @@ } + bb3: { -+ _31 = move _9; ++ _33 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + _34 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ _35 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ (((*_34) as variant#3).0: ActionPermit<'_, T>) = move ((*_35).0: ActionPermit<'_, T>); ++ (((*_33) as variant#3).0: ActionPermit<'_, T>) = move ((*_34).0: ActionPermit<'_, T>); + StorageLive(_12); + StorageLive(_13); + StorageLive(_14); + _14 = (); -+ StorageLive(_41); -+ _41 = Option::<()>::Some(copy _14); -+ _13 = std::future::Ready::<()>(move _41); -+ StorageDead(_41); ++ StorageLive(_40); ++ _40 = Option::<()>::Some(copy _14); ++ _13 = std::future::Ready::<()>(move _40); ++ StorageDead(_40); + StorageDead(_14); + _12 = move _13; + StorageDead(_13); -+ _36 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ (((*_36) as variant#3).1: std::future::Ready<()>) = move _12; ++ _35 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ (((*_35) as variant#3).1: std::future::Ready<()>) = move _12; + goto -> bb4; + } + @@ -214,39 +210,39 @@ + StorageLive(_19); + StorageLive(_20); + StorageLive(_21); -+ _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>); ++ _36 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ _21 = &mut (((*_36) as variant#3).1: std::future::Ready<()>); + _20 = &mut (*_21); + _19 = Pin::<&mut std::future::Ready<()>> { pointer: copy _20 }; + StorageDead(_20); + StorageLive(_22); + StorageLive(_23); + StorageLive(_24); -+ _24 = copy _31; ++ _24 = copy _9; + _23 = move _24; + _22 = &mut (*_23); + StorageDead(_24); ++ StorageLive(_44); + StorageLive(_45); -+ StorageLive(_46); -+ StorageLive(_50); ++ StorageLive(_49); ++ StorageLive(_41); + StorageLive(_42); + StorageLive(_43); -+ StorageLive(_44); -+ _46 = &mut _19; ++ _45 = &mut _19; ++ StorageLive(_46); ++ _46 = &mut (_19.0: &mut std::future::Ready<()>); ++ _44 = copy (_19.0: &mut std::future::Ready<()>); ++ StorageDead(_46); ++ _43 = &mut ((*_44).0: std::option::Option<()>); + StorageLive(_47); -+ _47 = &mut (_19.0: &mut std::future::Ready<()>); -+ _45 = copy (_19.0: &mut std::future::Ready<()>); ++ _47 = Option::<()>::None; ++ _42 = copy ((*_44).0: std::option::Option<()>); ++ ((*_44).0: std::option::Option<()>) = copy _47; + StorageDead(_47); -+ _44 = &mut ((*_45).0: std::option::Option<()>); ++ StorageDead(_43); + StorageLive(_48); -+ _48 = Option::<()>::None; -+ _43 = copy ((*_45).0: std::option::Option<()>); -+ ((*_45).0: std::option::Option<()>) = copy _48; -+ StorageDead(_48); -+ StorageDead(_44); -+ StorageLive(_49); -+ _49 = discriminant(_43); -+ switchInt(move _49) -> [0: bb11, 1: bb12, otherwise: bb5]; ++ _48 = discriminant(_42); ++ switchInt(move _48) -> [0: bb11, 1: bb12, otherwise: bb5]; } + + bb5: { @@ -266,8 +262,8 @@ + StorageDead(_12); + StorageDead(_28); + StorageDead(_29); -+ _38 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ discriminant((*_38)) = 3; ++ _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ discriminant((*_37)) = 3; + goto -> bb2; + } + @@ -281,14 +277,14 @@ + StorageDead(_18); + StorageDead(_17); + StorageDead(_12); -+ _39 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ drop((((*_39) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb8, unwind unreachable]; ++ _38 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ drop((((*_38) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb8, unwind unreachable]; + } + + bb8: { + _7 = Poll::<()>::Ready(move _30); -+ _40 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ discriminant((*_40)) = 1; ++ _39 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ discriminant((*_39)) = 1; + goto -> bb2; + } + @@ -298,7 +294,7 @@ + StorageLive(_29); + _28 = move _9; + StorageDead(_29); -+ _31 = move _28; ++ _9 = move _28; + StorageDead(_28); + _16 = const (); + goto -> bb4; @@ -309,18 +305,18 @@ + } + + bb11: { -+ _50 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; ++ _49 = option::expect_failed(const "`Ready` polled after completion") -> unwind unreachable; + } + + bb12: { -+ _42 = move ((_43 as Some).0: ()); -+ StorageDead(_49); -+ StorageDead(_43); -+ _18 = Poll::<()>::Ready(move _42); ++ _41 = move ((_42 as Some).0: ()); ++ StorageDead(_48); + StorageDead(_42); -+ StorageDead(_50); -+ StorageDead(_46); ++ _18 = Poll::<()>::Ready(move _41); ++ StorageDead(_41); ++ StorageDead(_49); + StorageDead(_45); ++ StorageDead(_44); + StorageDead(_22); + StorageDead(_19); + _25 = discriminant(_18); diff --git a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff index 8b027e988b8..d7ae931aaae 100644 --- a/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff +++ b/tests/mir-opt/inline_coroutine_body.run2-{closure#0}.Inline.panic-unwind.diff @@ -39,8 +39,8 @@ + let mut _28: &mut std::task::Context<'_>; + let mut _29: (); + let mut _30: (); -+ let mut _31: &mut std::task::Context<'_>; -+ let mut _32: u32; ++ let mut _31: u32; ++ let mut _32: &mut {async fn body of ActionPermit<'_, T>::perform()}; + let mut _33: &mut {async fn body of ActionPermit<'_, T>::perform()}; + let mut _34: &mut {async fn body of ActionPermit<'_, T>::perform()}; + let mut _35: &mut {async fn body of ActionPermit<'_, T>::perform()}; @@ -50,7 +50,6 @@ + let mut _39: &mut {async fn body of ActionPermit<'_, T>::perform()}; + let mut _40: &mut {async fn body of ActionPermit<'_, T>::perform()}; + let mut _41: &mut {async fn body of ActionPermit<'_, T>::perform()}; -+ let mut _42: &mut {async fn body of ActionPermit<'_, T>::perform()}; + scope 7 { + let mut _15: std::future::Ready<()>; + scope 8 { @@ -60,14 +59,14 @@ + scope 12 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } + scope 13 (inlined <std::future::Ready<()> as Future>::poll) { -+ let mut _44: (); -+ let mut _45: std::option::Option<()>; -+ let mut _46: &mut std::option::Option<()>; -+ let mut _47: &mut std::future::Ready<()>; -+ let mut _48: &mut std::pin::Pin<&mut std::future::Ready<()>>; ++ let mut _43: (); ++ let mut _44: std::option::Option<()>; ++ let mut _45: &mut std::option::Option<()>; ++ let mut _46: &mut std::future::Ready<()>; ++ let mut _47: &mut std::pin::Pin<&mut std::future::Ready<()>>; + scope 14 (inlined <Pin<&mut std::future::Ready<()>> as DerefMut>::deref_mut) { + scope 15 (inlined Pin::<&mut std::future::Ready<()>>::as_mut) { -+ let mut _49: &mut &mut std::future::Ready<()>; ++ let mut _48: &mut &mut std::future::Ready<()>; + scope 16 (inlined Pin::<&mut std::future::Ready<()>>::new_unchecked) { + } + scope 18 (inlined <&mut std::future::Ready<()> as DerefMut>::deref_mut) { @@ -77,22 +76,22 @@ + } + } + scope 19 (inlined Option::<()>::take) { -+ let mut _50: std::option::Option<()>; ++ let mut _49: std::option::Option<()>; + scope 20 (inlined std::mem::replace::<Option<()>>) { + scope 21 { + } + } + } + scope 22 (inlined #[track_caller] Option::<()>::expect) { -+ let mut _51: isize; -+ let mut _52: !; ++ let mut _50: isize; ++ let mut _51: !; + scope 23 { + } + } + } + } + scope 10 (inlined ready::<()>) { -+ let mut _43: std::option::Option<()>; ++ let mut _42: std::option::Option<()>; + } + scope 11 (inlined <std::future::Ready<()> as IntoFuture>::into_future) { + } @@ -149,10 +148,9 @@ + StorageLive(_39); + StorageLive(_40); + StorageLive(_41); -+ StorageLive(_42); -+ _33 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ _32 = discriminant((*_33)); -+ switchInt(move _32) -> [0: bb5, 1: bb15, 2: bb14, 3: bb13, otherwise: bb7]; ++ _32 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ _31 = discriminant((*_32)); ++ switchInt(move _31) -> [0: bb5, 1: bb15, 2: bb14, 3: bb13, otherwise: bb7]; } - bb3: { @@ -170,7 +168,6 @@ + } + + bb4: { -+ StorageDead(_42); + StorageDead(_41); + StorageDead(_40); + StorageDead(_39); @@ -203,23 +200,22 @@ - StorageDead(_2); - return; + bb5: { -+ _31 = move _9; ++ _33 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); + _34 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ _35 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ (((*_34) as variant#3).0: ActionPermit<'_, T>) = move ((*_35).0: ActionPermit<'_, T>); ++ (((*_33) as variant#3).0: ActionPermit<'_, T>) = move ((*_34).0: ActionPermit<'_, T>); + StorageLive(_12); + StorageLive(_13); + StorageLive(_14); + _14 = (); -+ StorageLive(_43); -+ _43 = Option::<()>::Some(copy _14); -+ _13 = std::future::Ready::<()>(move _43); -+ StorageDead(_43); ++ StorageLive(_42); ++ _42 = Option::<()>::Some(copy _14); ++ _13 = std::future::Ready::<()>(move _42); ++ StorageDead(_42); + StorageDead(_14); + _12 = move _13; + StorageDead(_13); -+ _36 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ (((*_36) as variant#3).1: std::future::Ready<()>) = move _12; ++ _35 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ (((*_35) as variant#3).1: std::future::Ready<()>) = move _12; + goto -> bb6; } @@ -231,39 +227,39 @@ + StorageLive(_19); + StorageLive(_20); + StorageLive(_21); -+ _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ _21 = &mut (((*_37) as variant#3).1: std::future::Ready<()>); ++ _36 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ _21 = &mut (((*_36) as variant#3).1: std::future::Ready<()>); + _20 = &mut (*_21); + _19 = Pin::<&mut std::future::Ready<()>> { pointer: copy _20 }; + StorageDead(_20); + StorageLive(_22); + StorageLive(_23); + StorageLive(_24); -+ _24 = copy _31; ++ _24 = copy _9; + _23 = move _24; + _22 = &mut (*_23); + StorageDead(_24); ++ StorageLive(_46); + StorageLive(_47); -+ StorageLive(_48); -+ StorageLive(_52); ++ StorageLive(_51); ++ StorageLive(_43); + StorageLive(_44); + StorageLive(_45); -+ StorageLive(_46); -+ _48 = &mut _19; ++ _47 = &mut _19; ++ StorageLive(_48); ++ _48 = &mut (_19.0: &mut std::future::Ready<()>); ++ _46 = copy (_19.0: &mut std::future::Ready<()>); ++ StorageDead(_48); ++ _45 = &mut ((*_46).0: std::option::Option<()>); + StorageLive(_49); -+ _49 = &mut (_19.0: &mut std::future::Ready<()>); -+ _47 = copy (_19.0: &mut std::future::Ready<()>); ++ _49 = Option::<()>::None; ++ _44 = copy ((*_46).0: std::option::Option<()>); ++ ((*_46).0: std::option::Option<()>) = copy _49; + StorageDead(_49); -+ _46 = &mut ((*_47).0: std::option::Option<()>); ++ StorageDead(_45); + StorageLive(_50); -+ _50 = Option::<()>::None; -+ _45 = copy ((*_47).0: std::option::Option<()>); -+ ((*_47).0: std::option::Option<()>) = copy _50; -+ StorageDead(_50); -+ StorageDead(_46); -+ StorageLive(_51); -+ _51 = discriminant(_45); -+ switchInt(move _51) -> [0: bb16, 1: bb17, otherwise: bb7]; ++ _50 = discriminant(_44); ++ switchInt(move _50) -> [0: bb16, 1: bb17, otherwise: bb7]; } - bb6 (cleanup): { @@ -285,8 +281,8 @@ + StorageDead(_12); + StorageDead(_28); + StorageDead(_29); -+ _38 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ discriminant((*_38)) = 3; ++ _37 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ discriminant((*_37)) = 3; + goto -> bb4; + } + @@ -300,14 +296,14 @@ + StorageDead(_18); + StorageDead(_17); + StorageDead(_12); -+ _39 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ drop((((*_39) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb10, unwind: bb12]; ++ _38 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ drop((((*_38) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb10, unwind: bb12]; + } + + bb10: { + _7 = Poll::<()>::Ready(move _30); -+ _40 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ discriminant((*_40)) = 1; ++ _39 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ discriminant((*_39)) = 1; + goto -> bb4; + } + @@ -319,13 +315,13 @@ + StorageDead(_18); + StorageDead(_17); + StorageDead(_12); -+ _41 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ drop((((*_41) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb12, unwind terminate(cleanup)]; ++ _40 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ drop((((*_40) as variant#3).0: ActionPermit<'_, T>)) -> [return: bb12, unwind terminate(cleanup)]; + } + + bb12 (cleanup): { -+ _42 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); -+ discriminant((*_42)) = 2; ++ _41 = deref_copy (_8.0: &mut {async fn body of ActionPermit<'_, T>::perform()}); ++ discriminant((*_41)) = 2; + goto -> bb2; + } + @@ -335,7 +331,7 @@ + StorageLive(_29); + _28 = move _9; + StorageDead(_29); -+ _31 = move _28; ++ _9 = move _28; + StorageDead(_28); + _16 = const (); + goto -> bb6; @@ -350,18 +346,18 @@ + } + + bb16: { -+ _52 = option::expect_failed(const "`Ready` polled after completion") -> bb11; ++ _51 = option::expect_failed(const "`Ready` polled after completion") -> bb11; + } + + bb17: { -+ _44 = move ((_45 as Some).0: ()); -+ StorageDead(_51); -+ StorageDead(_45); -+ _18 = Poll::<()>::Ready(move _44); ++ _43 = move ((_44 as Some).0: ()); ++ StorageDead(_50); + StorageDead(_44); -+ StorageDead(_52); -+ StorageDead(_48); ++ _18 = Poll::<()>::Ready(move _43); ++ StorageDead(_43); ++ StorageDead(_51); + StorageDead(_47); ++ StorageDead(_46); + StorageDead(_22); + StorageDead(_19); + _25 = discriminant(_18); diff --git a/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff new file mode 100644 index 00000000000..feba0fe7c4a --- /dev/null +++ b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-abort.diff @@ -0,0 +1,71 @@ +- // MIR for `norm2` before InstSimplify-after-simplifycfg ++ // MIR for `norm2` after InstSimplify-after-simplifycfg + + fn norm2(_1: [f32; 2]) -> f32 { + debug x => _1; + let mut _0: f32; + let _2: f32; + let _3: usize; + let mut _4: bool; + let _6: usize; + let mut _7: bool; + let mut _8: f32; + let mut _9: f32; + let mut _10: f32; + let mut _11: f32; + let mut _12: f32; + let mut _13: f32; + scope 1 { + debug a => _2; + let _5: f32; + scope 2 { + debug b => _5; + } + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = const 0_usize; + _4 = Lt(copy _3, const 2_usize); + assert(move _4, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _3) -> [success: bb1, unwind unreachable]; + } + + bb1: { + _2 = copy _1[_3]; + StorageDead(_3); + StorageLive(_5); + StorageLive(_6); + _6 = const 1_usize; + _7 = Lt(copy _6, const 2_usize); + assert(move _7, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _6) -> [success: bb2, unwind unreachable]; + } + + bb2: { + _5 = copy _1[_6]; + StorageDead(_6); + StorageLive(_8); + StorageLive(_9); + _9 = copy _2; + StorageLive(_10); + _10 = copy _2; + _8 = Mul(move _9, move _10); + StorageDead(_10); + StorageDead(_9); + StorageLive(_11); + StorageLive(_12); + _12 = copy _5; + StorageLive(_13); + _13 = copy _5; + _11 = Mul(move _12, move _13); + StorageDead(_13); + StorageDead(_12); + _0 = Add(move _8, move _11); + StorageDead(_11); + StorageDead(_8); + StorageDead(_5); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff new file mode 100644 index 00000000000..0ccf6a825c4 --- /dev/null +++ b/tests/mir-opt/instsimplify/combine_array_len.norm2.InstSimplify-after-simplifycfg.panic-unwind.diff @@ -0,0 +1,71 @@ +- // MIR for `norm2` before InstSimplify-after-simplifycfg ++ // MIR for `norm2` after InstSimplify-after-simplifycfg + + fn norm2(_1: [f32; 2]) -> f32 { + debug x => _1; + let mut _0: f32; + let _2: f32; + let _3: usize; + let mut _4: bool; + let _6: usize; + let mut _7: bool; + let mut _8: f32; + let mut _9: f32; + let mut _10: f32; + let mut _11: f32; + let mut _12: f32; + let mut _13: f32; + scope 1 { + debug a => _2; + let _5: f32; + scope 2 { + debug b => _5; + } + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = const 0_usize; + _4 = Lt(copy _3, const 2_usize); + assert(move _4, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _3) -> [success: bb1, unwind continue]; + } + + bb1: { + _2 = copy _1[_3]; + StorageDead(_3); + StorageLive(_5); + StorageLive(_6); + _6 = const 1_usize; + _7 = Lt(copy _6, const 2_usize); + assert(move _7, "index out of bounds: the length is {} but the index is {}", const 2_usize, copy _6) -> [success: bb2, unwind continue]; + } + + bb2: { + _5 = copy _1[_6]; + StorageDead(_6); + StorageLive(_8); + StorageLive(_9); + _9 = copy _2; + StorageLive(_10); + _10 = copy _2; + _8 = Mul(move _9, move _10); + StorageDead(_10); + StorageDead(_9); + StorageLive(_11); + StorageLive(_12); + _12 = copy _5; + StorageLive(_13); + _13 = copy _5; + _11 = Mul(move _12, move _13); + StorageDead(_13); + StorageDead(_12); + _0 = Add(move _8, move _11); + StorageDead(_11); + StorageDead(_8); + StorageDead(_5); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/instsimplify/combine_array_len.normN.InstSimplify-after-simplifycfg.panic-abort.diff b/tests/mir-opt/instsimplify/combine_array_len.normN.InstSimplify-after-simplifycfg.panic-abort.diff new file mode 100644 index 00000000000..e9cb2c58177 --- /dev/null +++ b/tests/mir-opt/instsimplify/combine_array_len.normN.InstSimplify-after-simplifycfg.panic-abort.diff @@ -0,0 +1,71 @@ +- // MIR for `normN` before InstSimplify-after-simplifycfg ++ // MIR for `normN` after InstSimplify-after-simplifycfg + + fn normN(_1: [f32; N]) -> f32 { + debug x => _1; + let mut _0: f32; + let _2: f32; + let _3: usize; + let mut _4: bool; + let _6: usize; + let mut _7: bool; + let mut _8: f32; + let mut _9: f32; + let mut _10: f32; + let mut _11: f32; + let mut _12: f32; + let mut _13: f32; + scope 1 { + debug a => _2; + let _5: f32; + scope 2 { + debug b => _5; + } + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = const 0_usize; + _4 = Lt(copy _3, const N); + assert(move _4, "index out of bounds: the length is {} but the index is {}", const N, copy _3) -> [success: bb1, unwind unreachable]; + } + + bb1: { + _2 = copy _1[_3]; + StorageDead(_3); + StorageLive(_5); + StorageLive(_6); + _6 = const 1_usize; + _7 = Lt(copy _6, const N); + assert(move _7, "index out of bounds: the length is {} but the index is {}", const N, copy _6) -> [success: bb2, unwind unreachable]; + } + + bb2: { + _5 = copy _1[_6]; + StorageDead(_6); + StorageLive(_8); + StorageLive(_9); + _9 = copy _2; + StorageLive(_10); + _10 = copy _2; + _8 = Mul(move _9, move _10); + StorageDead(_10); + StorageDead(_9); + StorageLive(_11); + StorageLive(_12); + _12 = copy _5; + StorageLive(_13); + _13 = copy _5; + _11 = Mul(move _12, move _13); + StorageDead(_13); + StorageDead(_12); + _0 = Add(move _8, move _11); + StorageDead(_11); + StorageDead(_8); + StorageDead(_5); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/instsimplify/combine_array_len.normN.InstSimplify-after-simplifycfg.panic-unwind.diff b/tests/mir-opt/instsimplify/combine_array_len.normN.InstSimplify-after-simplifycfg.panic-unwind.diff new file mode 100644 index 00000000000..0ddc70f2003 --- /dev/null +++ b/tests/mir-opt/instsimplify/combine_array_len.normN.InstSimplify-after-simplifycfg.panic-unwind.diff @@ -0,0 +1,71 @@ +- // MIR for `normN` before InstSimplify-after-simplifycfg ++ // MIR for `normN` after InstSimplify-after-simplifycfg + + fn normN(_1: [f32; N]) -> f32 { + debug x => _1; + let mut _0: f32; + let _2: f32; + let _3: usize; + let mut _4: bool; + let _6: usize; + let mut _7: bool; + let mut _8: f32; + let mut _9: f32; + let mut _10: f32; + let mut _11: f32; + let mut _12: f32; + let mut _13: f32; + scope 1 { + debug a => _2; + let _5: f32; + scope 2 { + debug b => _5; + } + } + + bb0: { + StorageLive(_2); + StorageLive(_3); + _3 = const 0_usize; + _4 = Lt(copy _3, const N); + assert(move _4, "index out of bounds: the length is {} but the index is {}", const N, copy _3) -> [success: bb1, unwind continue]; + } + + bb1: { + _2 = copy _1[_3]; + StorageDead(_3); + StorageLive(_5); + StorageLive(_6); + _6 = const 1_usize; + _7 = Lt(copy _6, const N); + assert(move _7, "index out of bounds: the length is {} but the index is {}", const N, copy _6) -> [success: bb2, unwind continue]; + } + + bb2: { + _5 = copy _1[_6]; + StorageDead(_6); + StorageLive(_8); + StorageLive(_9); + _9 = copy _2; + StorageLive(_10); + _10 = copy _2; + _8 = Mul(move _9, move _10); + StorageDead(_10); + StorageDead(_9); + StorageLive(_11); + StorageLive(_12); + _12 = copy _5; + StorageLive(_13); + _13 = copy _5; + _11 = Mul(move _12, move _13); + StorageDead(_13); + StorageDead(_12); + _0 = Add(move _8, move _11); + StorageDead(_11); + StorageDead(_8); + StorageDead(_5); + StorageDead(_2); + return; + } + } + diff --git a/tests/mir-opt/instsimplify/combine_array_len.rs b/tests/mir-opt/instsimplify/combine_array_len.rs new file mode 100644 index 00000000000..1c4d42d3bbe --- /dev/null +++ b/tests/mir-opt/instsimplify/combine_array_len.rs @@ -0,0 +1,25 @@ +// EMIT_MIR_FOR_EACH_PANIC_STRATEGY +//@ test-mir-pass: InstSimplify-after-simplifycfg + +// EMIT_MIR combine_array_len.norm2.InstSimplify-after-simplifycfg.diff +fn norm2(x: [f32; 2]) -> f32 { + // CHECK-LABEL: fn norm2( + // CHECK-NOT: PtrMetadata( + let a = x[0]; + let b = x[1]; + a * a + b * b +} + +// EMIT_MIR combine_array_len.normN.InstSimplify-after-simplifycfg.diff +fn normN<const N: usize>(x: [f32; N]) -> f32 { + // CHECK-LABEL: fn normN( + // CHECK-NOT: PtrMetadata( + let a = x[0]; + let b = x[1]; + a * a + b * b +} + +fn main() { + assert_eq!(norm2([3.0, 4.0]), 5.0 * 5.0); + assert_eq!(normN([3.0, 4.0]), 5.0 * 5.0); +} diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff index 08dee3697e0..5cf36b9aebf 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-abort.diff @@ -7,18 +7,16 @@ let _2: &[T]; let _3: &[T; 3]; let _4: [T; 3]; - let mut _5: usize; - let mut _6: bool; - let mut _10: !; + let mut _8: !; scope 1 { debug v => _2; + let _5: &T; + let _6: &T; let _7: &T; - let _8: &T; - let _9: &T; scope 2 { - debug v1 => _7; - debug v2 => _8; - debug v3 => _9; + debug v1 => _5; + debug v2 => _6; + debug v3 => _7; } } @@ -27,25 +25,23 @@ _4 = [copy _1, copy _1, copy _1]; _3 = &_4; _2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit)); - nop; - nop; goto -> bb2; } bb1: { - _10 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind unreachable; + _8 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind unreachable; } bb2: { + StorageLive(_5); + _5 = &(*_2)[0 of 3]; + StorageLive(_6); + _6 = &(*_2)[1 of 3]; StorageLive(_7); - _7 = &(*_2)[0 of 3]; - StorageLive(_8); - _8 = &(*_2)[1 of 3]; - StorageLive(_9); - _9 = &(*_2)[2 of 3]; - StorageDead(_9); - StorageDead(_8); + _7 = &(*_2)[2 of 3]; StorageDead(_7); + StorageDead(_6); + StorageDead(_5); StorageDead(_4); return; } diff --git a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff index aa44a2ad532..0598a3aa3f1 100644 --- a/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff +++ b/tests/mir-opt/issue_76432.test.SimplifyComparisonIntegral.panic-unwind.diff @@ -7,18 +7,16 @@ let _2: &[T]; let _3: &[T; 3]; let _4: [T; 3]; - let mut _5: usize; - let mut _6: bool; - let mut _10: !; + let mut _8: !; scope 1 { debug v => _2; + let _5: &T; + let _6: &T; let _7: &T; - let _8: &T; - let _9: &T; scope 2 { - debug v1 => _7; - debug v2 => _8; - debug v3 => _9; + debug v1 => _5; + debug v2 => _6; + debug v3 => _7; } } @@ -27,25 +25,23 @@ _4 = [copy _1, copy _1, copy _1]; _3 = &_4; _2 = copy _3 as &[T] (PointerCoercion(Unsize, Implicit)); - nop; - nop; goto -> bb2; } bb1: { - _10 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue; + _8 = core::panicking::panic(const "internal error: entered unreachable code") -> unwind continue; } bb2: { + StorageLive(_5); + _5 = &(*_2)[0 of 3]; + StorageLive(_6); + _6 = &(*_2)[1 of 3]; StorageLive(_7); - _7 = &(*_2)[0 of 3]; - StorageLive(_8); - _8 = &(*_2)[1 of 3]; - StorageLive(_9); - _9 = &(*_2)[2 of 3]; - StorageDead(_9); - StorageDead(_8); + _7 = &(*_2)[2 of 3]; StorageDead(_7); + StorageDead(_6); + StorageDead(_5); StorageDead(_4); return; } diff --git a/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-abort.diff index 180a7db0297..714a12804e6 100644 --- a/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-abort.diff @@ -18,8 +18,7 @@ } bb0: { -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); StorageLive(_4); _4 = &_1; @@ -41,8 +40,7 @@ bb1: { StorageDead(_6); StorageDead(_5); -- StorageDead(_2); -+ nop; + StorageDead(_2); StorageDead(_7); return; } diff --git a/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-unwind.diff index 180a7db0297..714a12804e6 100644 --- a/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_len_raw.GVN.panic-unwind.diff @@ -18,8 +18,7 @@ } bb0: { -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); StorageLive(_4); _4 = &_1; @@ -41,8 +40,7 @@ bb1: { StorageDead(_6); StorageDead(_5); -- StorageDead(_2); -+ nop; + StorageDead(_2); StorageDead(_7); return; } diff --git a/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-abort.diff b/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-abort.diff index 49964f8b49e..b236b22f067 100644 --- a/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-abort.diff +++ b/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-abort.diff @@ -17,8 +17,7 @@ } bb0: { -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); StorageLive(_4); _4 = &mut _1; @@ -38,8 +37,7 @@ bb1: { StorageDead(_6); StorageDead(_5); -- StorageDead(_2); -+ nop; + StorageDead(_2); return; } } diff --git a/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-unwind.diff b/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-unwind.diff index 49964f8b49e..b236b22f067 100644 --- a/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-unwind.diff +++ b/tests/mir-opt/lower_array_len.array_len_reborrow.GVN.panic-unwind.diff @@ -17,8 +17,7 @@ } bb0: { -- StorageLive(_2); -+ nop; + StorageLive(_2); StorageLive(_3); StorageLive(_4); _4 = &mut _1; @@ -38,8 +37,7 @@ bb1: { StorageDead(_6); StorageDead(_5); -- StorageDead(_2); -+ nop; + StorageDead(_2); return; } } diff --git a/tests/mir-opt/pre-codegen/checked_ops.rs b/tests/mir-opt/pre-codegen/checked_ops.rs index 8fd340503f5..dfbc0f4a110 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.rs +++ b/tests/mir-opt/pre-codegen/checked_ops.rs @@ -44,8 +44,7 @@ pub fn saturating_sub_at_home(lhs: u32, rhs: u32) -> u32 { // CHECK-LABEL: fn saturating_sub_at_home // CHECK: [[DELTA:_[0-9]+]] = SubUnchecked(copy _1, copy _2) // CHECK: [[TEMP1:_.+]] = Option::<u32>::Some({{move|copy}} [[DELTA]]); - // CHECK: [[TEMP2:_.+]] = {{move|copy}} (([[TEMP1]] as Some).0: u32); - // CHECK: _0 = {{move|copy}} [[TEMP2]]; + // CHECK: _0 = {{move|copy}} (([[TEMP1]] as Some).0: u32); u32::checked_sub(lhs, rhs).unwrap_or(0) } diff --git a/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir index 5b4fdeda857..dc7567b57e7 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-abort.mir @@ -10,7 +10,6 @@ fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 { let mut _4: u32; } scope 2 (inlined Option::<u32>::unwrap_or) { - let _6: u32; scope 3 { } } @@ -28,10 +27,7 @@ fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 { _5 = Option::<u32>::Some(move _4); StorageDead(_4); StorageDead(_3); - StorageLive(_6); - _6 = move ((_5 as Some).0: u32); - _0 = move _6; - StorageDead(_6); + _0 = move ((_5 as Some).0: u32); goto -> bb3; } diff --git a/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir index 5b4fdeda857..dc7567b57e7 100644 --- a/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/checked_ops.saturating_sub_at_home.PreCodegen.after.panic-unwind.mir @@ -10,7 +10,6 @@ fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 { let mut _4: u32; } scope 2 (inlined Option::<u32>::unwrap_or) { - let _6: u32; scope 3 { } } @@ -28,10 +27,7 @@ fn saturating_sub_at_home(_1: u32, _2: u32) -> u32 { _5 = Option::<u32>::Some(move _4); StorageDead(_4); StorageDead(_3); - StorageLive(_6); - _6 = move ((_5 as Some).0: u32); - _0 = move _6; - StorageDead(_6); + _0 = move ((_5 as Some).0: u32); goto -> bb3; } diff --git a/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir index 8746cb08991..e235fa35c02 100644 --- a/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/derived_ord.demo_le.PreCodegen.after.mir @@ -5,8 +5,9 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { debug b => _2; let mut _0: bool; scope 1 (inlined <MultiField as PartialOrd>::le) { - let mut _11: std::option::Option<std::cmp::Ordering>; + let mut _6: std::option::Option<std::cmp::Ordering>; scope 2 (inlined Option::<std::cmp::Ordering>::is_some_and::<fn(std::cmp::Ordering) -> bool {std::cmp::Ordering::is_le}>) { + let mut _11: isize; let _12: std::cmp::Ordering; scope 3 { scope 4 (inlined <fn(std::cmp::Ordering) -> bool {std::cmp::Ordering::is_le} as FnOnce<(std::cmp::Ordering,)>>::call_once - shim(fn(std::cmp::Ordering) -> bool {std::cmp::Ordering::is_le})) { @@ -19,7 +20,6 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { } } scope 7 (inlined <MultiField as PartialOrd>::partial_cmp) { - let mut _6: std::option::Option<std::cmp::Ordering>; let mut _7: i8; scope 8 { } @@ -38,9 +38,8 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { bb0: { StorageLive(_12); - StorageLive(_11); - StorageLive(_5); StorageLive(_6); + StorageLive(_5); StorageLive(_7); StorageLive(_3); _3 = copy ((*_1).0: char); @@ -63,30 +62,44 @@ fn demo_le(_1: &MultiField, _2: &MultiField) -> bool { _10 = Cmp(move _8, move _9); StorageDead(_9); StorageDead(_8); - _11 = Option::<std::cmp::Ordering>::Some(move _10); + _6 = Option::<std::cmp::Ordering>::Some(move _10); StorageDead(_10); StorageDead(_7); - StorageDead(_6); StorageDead(_5); - goto -> bb3; + StorageLive(_11); + goto -> bb4; } bb2: { - _11 = copy _6; StorageDead(_7); - StorageDead(_6); StorageDead(_5); - goto -> bb3; + StorageLive(_11); + _11 = discriminant(_6); + switchInt(move _11) -> [0: bb3, 1: bb4, otherwise: bb6]; } bb3: { - _12 = move ((_11 as Some).0: std::cmp::Ordering); + _0 = const false; + goto -> bb5; + } + + bb4: { + _12 = move ((_6 as Some).0: std::cmp::Ordering); StorageLive(_13); _13 = discriminant(_12); _0 = Le(move _13, const 0_i8); StorageDead(_13); + goto -> bb5; + } + + bb5: { StorageDead(_11); + StorageDead(_6); StorageDead(_12); return; } + + bb6: { + unreachable; + } } diff --git a/tests/mir-opt/pre-codegen/derived_ord.rs b/tests/mir-opt/pre-codegen/derived_ord.rs index 73ae923a6cb..823e0f6d09c 100644 --- a/tests/mir-opt/pre-codegen/derived_ord.rs +++ b/tests/mir-opt/pre-codegen/derived_ord.rs @@ -25,7 +25,10 @@ pub fn demo_le(a: &MultiField, b: &MultiField) -> bool { // CHECK: Cmp(move [[A1]], move [[B1]]); // CHECK: [[D1:_[0-9]+]] = discriminant({{.+}}); - // CHECK: _0 = Le(move [[D1]], const 0_i8); + // CHECK: switchInt(move [[D1]]) -> [0: bb{{[0-9]+}}, 1: bb{{[0-9]+}}, otherwise: bb{{[0-9]+}}]; + + // CHECK: [[D2:_[0-9]+]] = discriminant({{.+}}); + // CHECK: _0 = Le(move [[D2]], const 0_i8); *a <= *b } diff --git a/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir index de25eebee77..5993bd79d27 100644 --- a/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/derived_ord.{impl#0}-partial_cmp.PreCodegen.after.mir @@ -4,10 +4,9 @@ fn <impl at $DIR/derived_ord.rs:5:10: 5:20>::partial_cmp(_1: &MultiField, _2: &M debug self => _1; debug other => _2; let mut _0: std::option::Option<std::cmp::Ordering>; - let mut _6: std::option::Option<std::cmp::Ordering>; - let mut _7: i8; + let mut _6: i8; scope 1 { - debug cmp => _6; + debug cmp => _0; } scope 2 (inlined std::cmp::impls::<impl PartialOrd for char>::partial_cmp) { let mut _3: char; @@ -15,9 +14,9 @@ fn <impl at $DIR/derived_ord.rs:5:10: 5:20>::partial_cmp(_1: &MultiField, _2: &M let mut _5: std::cmp::Ordering; } scope 3 (inlined std::cmp::impls::<impl PartialOrd for i16>::partial_cmp) { + let mut _7: i16; let mut _8: i16; - let mut _9: i16; - let mut _10: std::cmp::Ordering; + let mut _9: std::cmp::Ordering; } bb0: { @@ -28,27 +27,26 @@ fn <impl at $DIR/derived_ord.rs:5:10: 5:20>::partial_cmp(_1: &MultiField, _2: &M _5 = Cmp(move _3, move _4); StorageDead(_4); StorageDead(_3); - _6 = Option::<std::cmp::Ordering>::Some(copy _5); - _7 = discriminant(_5); - switchInt(move _7) -> [0: bb1, otherwise: bb2]; + _0 = Option::<std::cmp::Ordering>::Some(copy _5); + _6 = discriminant(_5); + switchInt(move _6) -> [0: bb1, otherwise: bb2]; } bb1: { - StorageLive(_10); - StorageLive(_8); - _8 = copy ((*_1).1: i16); StorageLive(_9); - _9 = copy ((*_2).1: i16); - _10 = Cmp(move _8, move _9); - StorageDead(_9); + StorageLive(_7); + _7 = copy ((*_1).1: i16); + StorageLive(_8); + _8 = copy ((*_2).1: i16); + _9 = Cmp(move _7, move _8); StorageDead(_8); - _0 = Option::<std::cmp::Ordering>::Some(move _10); - StorageDead(_10); + StorageDead(_7); + _0 = Option::<std::cmp::Ordering>::Some(move _9); + StorageDead(_9); goto -> bb3; } bb2: { - _0 = copy _6; goto -> bb3; } diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir index dfe618612ab..03a52b82b49 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -5,23 +5,21 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { debug end => _2; debug f => _3; let mut _0: (); - let mut _4: u32; - let mut _9: std::option::Option<u32>; - let mut _11: &impl Fn(u32); - let mut _12: (u32,); - let _13: (); + let mut _7: std::option::Option<u32>; + let mut _9: &impl Fn(u32); + let mut _10: (u32,); + let _11: (); scope 1 { - debug ((iter: std::ops::Range<u32>).0: u32) => _4; + debug ((iter: std::ops::Range<u32>).0: u32) => _1; debug ((iter: std::ops::Range<u32>).1: u32) => _2; - let _10: u32; + let _8: u32; scope 2 { - debug x => _10; + debug x => _8; } scope 4 (inlined iter::range::<impl Iterator for std::ops::Range<u32>>::next) { scope 5 (inlined <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next) { - let mut _6: bool; - let _7: u32; - let mut _8: u32; + let mut _5: bool; + let _6: u32; scope 6 { scope 8 (inlined <u32 as Step>::forward_unchecked) { scope 9 (inlined #[track_caller] core::num::<impl u32>::unchecked_add) { @@ -33,7 +31,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { } } scope 7 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) { - let mut _5: u32; + let mut _4: u32; } } } @@ -42,25 +40,22 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { } bb0: { - StorageLive(_4); - _4 = copy _1; goto -> bb1; } bb1: { - StorageLive(_9); - StorageLive(_6); + StorageLive(_7); StorageLive(_5); - _5 = copy _4; - _6 = Lt(move _5, copy _2); - StorageDead(_5); - switchInt(move _6) -> [0: bb2, otherwise: bb4]; + StorageLive(_4); + _4 = copy _1; + _5 = Lt(move _4, copy _2); + StorageDead(_4); + switchInt(move _5) -> [0: bb2, otherwise: bb4]; } bb2: { - StorageDead(_6); - StorageDead(_9); - StorageDead(_4); + StorageDead(_5); + StorageDead(_7); drop(_3) -> [return: bb3, unwind unreachable]; } @@ -69,25 +64,22 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { } bb4: { - _7 = copy _4; - StorageLive(_8); - _8 = AddUnchecked(copy _7, const 1_u32); - _4 = move _8; - StorageDead(_8); - _9 = Option::<u32>::Some(copy _7); - StorageDead(_6); - _10 = copy ((_9 as Some).0: u32); - StorageLive(_11); - _11 = &_3; - StorageLive(_12); - _12 = (copy _10,); - _13 = <impl Fn(u32) as Fn<(u32,)>>::call(move _11, move _12) -> [return: bb5, unwind unreachable]; + _6 = copy _1; + _1 = AddUnchecked(copy _6, const 1_u32); + _7 = Option::<u32>::Some(copy _6); + StorageDead(_5); + _8 = copy ((_7 as Some).0: u32); + StorageLive(_9); + _9 = &_3; + StorageLive(_10); + _10 = (copy _8,); + _11 = <impl Fn(u32) as Fn<(u32,)>>::call(move _9, move _10) -> [return: bb5, unwind unreachable]; } bb5: { - StorageDead(_12); - StorageDead(_11); + StorageDead(_10); StorageDead(_9); + StorageDead(_7); goto -> bb1; } } diff --git a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir index e0fcfcaffc5..3b09f33e733 100644 --- a/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/range_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -5,23 +5,21 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { debug end => _2; debug f => _3; let mut _0: (); - let mut _4: u32; - let mut _9: std::option::Option<u32>; - let mut _11: &impl Fn(u32); - let mut _12: (u32,); - let _13: (); + let mut _7: std::option::Option<u32>; + let mut _9: &impl Fn(u32); + let mut _10: (u32,); + let _11: (); scope 1 { - debug ((iter: std::ops::Range<u32>).0: u32) => _4; + debug ((iter: std::ops::Range<u32>).0: u32) => _1; debug ((iter: std::ops::Range<u32>).1: u32) => _2; - let _10: u32; + let _8: u32; scope 2 { - debug x => _10; + debug x => _8; } scope 4 (inlined iter::range::<impl Iterator for std::ops::Range<u32>>::next) { scope 5 (inlined <std::ops::Range<u32> as iter::range::RangeIteratorImpl>::spec_next) { - let mut _6: bool; - let _7: u32; - let mut _8: u32; + let mut _5: bool; + let _6: u32; scope 6 { scope 8 (inlined <u32 as Step>::forward_unchecked) { scope 9 (inlined #[track_caller] core::num::<impl u32>::unchecked_add) { @@ -33,7 +31,7 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { } } scope 7 (inlined std::cmp::impls::<impl PartialOrd for u32>::lt) { - let mut _5: u32; + let mut _4: u32; } } } @@ -42,25 +40,22 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { } bb0: { - StorageLive(_4); - _4 = copy _1; goto -> bb1; } bb1: { - StorageLive(_9); - StorageLive(_6); + StorageLive(_7); StorageLive(_5); - _5 = copy _4; - _6 = Lt(move _5, copy _2); - StorageDead(_5); - switchInt(move _6) -> [0: bb2, otherwise: bb4]; + StorageLive(_4); + _4 = copy _1; + _5 = Lt(move _4, copy _2); + StorageDead(_4); + switchInt(move _5) -> [0: bb2, otherwise: bb4]; } bb2: { - StorageDead(_6); - StorageDead(_9); - StorageDead(_4); + StorageDead(_5); + StorageDead(_7); drop(_3) -> [return: bb3, unwind continue]; } @@ -69,25 +64,22 @@ fn forward_loop(_1: u32, _2: u32, _3: impl Fn(u32)) -> () { } bb4: { - _7 = copy _4; - StorageLive(_8); - _8 = AddUnchecked(copy _7, const 1_u32); - _4 = move _8; - StorageDead(_8); - _9 = Option::<u32>::Some(copy _7); - StorageDead(_6); - _10 = copy ((_9 as Some).0: u32); - StorageLive(_11); - _11 = &_3; - StorageLive(_12); - _12 = (copy _10,); - _13 = <impl Fn(u32) as Fn<(u32,)>>::call(move _11, move _12) -> [return: bb5, unwind: bb6]; + _6 = copy _1; + _1 = AddUnchecked(copy _6, const 1_u32); + _7 = Option::<u32>::Some(copy _6); + StorageDead(_5); + _8 = copy ((_7 as Some).0: u32); + StorageLive(_9); + _9 = &_3; + StorageLive(_10); + _10 = (copy _8,); + _11 = <impl Fn(u32) as Fn<(u32,)>>::call(move _9, move _10) -> [return: bb5, unwind: bb6]; } bb5: { - StorageDead(_12); - StorageDead(_11); + StorageDead(_10); StorageDead(_9); + StorageDead(_7); goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir index 72b39a7f6a8..104987b0fdd 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-abort.mir @@ -4,30 +4,28 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _11: std::ptr::NonNull<T>; - let mut _12: *const T; - let mut _13: usize; - let mut _32: std::option::Option<(usize, &T)>; - let mut _35: &impl Fn(usize, &T); - let mut _36: (usize, &T); - let _37: (); + let mut _10: usize; + let mut _28: std::option::Option<(usize, &T)>; + let mut _31: &impl Fn(usize, &T); + let mut _32: (usize, &T); + let _33: (); scope 1 { - debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _11; - debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).1: *const T) => _12; + debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _6; + debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).1: *const T) => _9; debug (((iter: Enumerate<std::slice::Iter<'_, T>>).0: std::slice::Iter<'_, T>).2: std::marker::PhantomData<&T>) => const ZeroSized: PhantomData<&T>; - debug ((iter: Enumerate<std::slice::Iter<'_, T>>).1: usize) => _13; - let _33: usize; - let _34: &T; + debug ((iter: Enumerate<std::slice::Iter<'_, T>>).1: usize) => _10; + let _29: usize; + let _30: &T; scope 2 { - debug i => _33; - debug x => _34; + debug i => _29; + debug x => _30; } scope 18 (inlined <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next) { - let mut _27: std::option::Option<&T>; - let mut _30: (usize, bool); - let mut _31: (usize, &T); + let mut _23: std::option::Option<&T>; + let mut _26: (usize, bool); + let mut _27: (usize, &T); scope 19 { - let _29: usize; + let _25: usize; scope 24 { } } @@ -42,21 +40,21 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } scope 25 (inlined <Option<&T> as Try>::branch) { - let _28: &T; + let _24: &T; scope 26 { } } scope 28 (inlined <std::slice::Iter<'_, T> as Iterator>::next) { - let _14: std::ptr::NonNull<T>; - let _16: std::ptr::NonNull<T>; - let mut _19: bool; - let mut _22: std::ptr::NonNull<T>; - let mut _24: usize; - let _26: &T; + let mut _6: std::ptr::NonNull<T>; + let _11: std::ptr::NonNull<T>; + let _13: std::ptr::NonNull<T>; + let mut _16: bool; + let mut _20: usize; + let _22: &T; scope 29 { - let _15: *const T; + let _12: *const T; scope 30 { - let _23: usize; + let _19: usize; scope 31 { scope 34 (inlined #[track_caller] core::num::<impl usize>::unchecked_sub) { scope 35 (inlined core::ub_checks::check_language_ub) { @@ -72,21 +70,21 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } } scope 38 (inlined <NonNull<T> as PartialEq>::eq) { - let mut _17: *mut T; - let mut _18: *mut T; + let mut _14: *mut T; + let mut _15: *mut T; scope 39 (inlined NonNull::<T>::as_ptr) { } scope 40 (inlined NonNull::<T>::as_ptr) { } } scope 41 (inlined NonNull::<T>::add) { - let mut _20: *const T; - let mut _21: *const T; + let mut _17: *const T; + let mut _18: *const T; scope 42 (inlined NonNull::<T>::as_ptr) { } } scope 43 (inlined NonNull::<T>::as_ref::<'_>) { - let _25: *const T; + let _21: *const T; scope 44 (inlined NonNull::<T>::as_ptr) { } scope 45 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) { @@ -102,9 +100,7 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { let _3: usize; let mut _7: *mut T; let mut _8: *mut T; - let mut _10: *const T; scope 5 { - let _6: std::ptr::NonNull<T>; scope 6 { let _9: *const T; scope 7 { @@ -145,7 +141,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _5 = copy _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: copy _5 }; StorageDead(_5); - StorageLive(_9); switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -166,97 +161,86 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb3: { - _10 = copy _9; - StorageDead(_9); StorageDead(_4); StorageDead(_3); - StorageLive(_11); - StorageLive(_12); - StorageLive(_13); - _11 = copy _6; - _12 = copy _10; - _13 = const 0_usize; + StorageLive(_10); + _10 = const 0_usize; goto -> bb4; } bb4: { - StorageLive(_32); - StorageLive(_29); - StorageLive(_30); - StorageLive(_27); - StorageLive(_14); - StorageLive(_15); - StorageLive(_23); - StorageLive(_24); - StorageLive(_16); + StorageLive(_28); + StorageLive(_25); StorageLive(_26); - _14 = copy _11; - _15 = copy _12; + StorageLive(_23); + StorageLive(_11); + StorageLive(_12); + StorageLive(_19); + StorageLive(_20); + StorageLive(_13); + StorageLive(_22); + _11 = copy _6; + _12 = copy _9; switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8]; } bb5: { - StorageLive(_19); - _16 = copy _15 as std::ptr::NonNull<T> (Transmute); - StorageLive(_17); - _17 = copy _14 as *mut T (Transmute); - StorageLive(_18); - _18 = copy _16 as *mut T (Transmute); - _19 = Eq(copy _17, copy _18); - StorageDead(_18); - StorageDead(_17); - switchInt(move _19) -> [0: bb6, otherwise: bb7]; + StorageLive(_16); + _13 = copy _12 as std::ptr::NonNull<T> (Transmute); + StorageLive(_14); + _14 = copy _11 as *mut T (Transmute); + StorageLive(_15); + _15 = copy _13 as *mut T (Transmute); + _16 = Eq(copy _14, copy _15); + StorageDead(_15); + StorageDead(_14); + switchInt(move _16) -> [0: bb6, otherwise: bb7]; } bb6: { - StorageDead(_19); - StorageLive(_22); - StorageLive(_21); - StorageLive(_20); - _20 = copy _14 as *const T (Transmute); - _21 = Offset(copy _20, const 1_usize); - StorageDead(_20); - _22 = NonNull::<T> { pointer: copy _21 }; - StorageDead(_21); - _11 = move _22; - StorageDead(_22); + StorageDead(_16); + StorageLive(_18); + StorageLive(_17); + _17 = copy _11 as *const T (Transmute); + _18 = Offset(copy _17, const 1_usize); + StorageDead(_17); + _6 = NonNull::<T> { pointer: copy _18 }; + StorageDead(_18); goto -> bb13; } bb7: { - StorageDead(_19); - StorageDead(_26); StorageDead(_16); - StorageDead(_24); - StorageDead(_23); - StorageDead(_15); - StorageDead(_14); + StorageDead(_22); + StorageDead(_13); + StorageDead(_20); + StorageDead(_19); + StorageDead(_12); + StorageDead(_11); goto -> bb10; } bb8: { - _23 = copy _15 as usize (Transmute); - switchInt(copy _23) -> [0: bb9, otherwise: bb12]; + _19 = copy _12 as usize (Transmute); + switchInt(copy _19) -> [0: bb9, otherwise: bb12]; } bb9: { - StorageDead(_26); - StorageDead(_16); - StorageDead(_24); - StorageDead(_23); - StorageDead(_15); - StorageDead(_14); + StorageDead(_22); + StorageDead(_13); + StorageDead(_20); + StorageDead(_19); + StorageDead(_12); + StorageDead(_11); goto -> bb10; } bb10: { - StorageDead(_27); - StorageDead(_30); - StorageDead(_29); - StorageDead(_32); - StorageDead(_11); - StorageDead(_12); - StorageDead(_13); + StorageDead(_23); + StorageDead(_26); + StorageDead(_25); + StorageDead(_28); + StorageDead(_10); drop(_2) -> [return: bb11, unwind unreachable]; } @@ -265,51 +249,51 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb12: { - _24 = SubUnchecked(copy _23, const 1_usize); - _12 = copy _24 as *const T (Transmute); + _20 = SubUnchecked(copy _19, const 1_usize); + _9 = copy _20 as *const T (Transmute); goto -> bb13; } bb13: { - StorageLive(_25); - _25 = copy _14 as *const T (Transmute); - _26 = &(*_25); - StorageDead(_25); - _27 = Option::<&T>::Some(copy _26); - StorageDead(_26); - StorageDead(_16); - StorageDead(_24); + StorageLive(_21); + _21 = copy _11 as *const T (Transmute); + _22 = &(*_21); + StorageDead(_21); + _23 = Option::<&T>::Some(copy _22); + StorageDead(_22); + StorageDead(_13); + StorageDead(_20); + StorageDead(_19); + StorageDead(_12); + StorageDead(_11); + _24 = copy ((_23 as Some).0: &T); StorageDead(_23); - StorageDead(_15); - StorageDead(_14); - _28 = copy ((_27 as Some).0: &T); - StorageDead(_27); - _29 = copy _13; - _30 = AddWithOverflow(copy _13, const 1_usize); - assert(!move (_30.1: bool), "attempt to compute `{} + {}`, which would overflow", copy _13, const 1_usize) -> [success: bb14, unwind unreachable]; + _25 = copy _10; + _26 = AddWithOverflow(copy _10, const 1_usize); + assert(!move (_26.1: bool), "attempt to compute `{} + {}`, which would overflow", copy _10, const 1_usize) -> [success: bb14, unwind unreachable]; } bb14: { - _13 = move (_30.0: usize); + _10 = move (_26.0: usize); + StorageLive(_27); + _27 = (copy _25, copy _24); + _28 = Option::<(usize, &T)>::Some(move _27); + StorageDead(_27); + StorageDead(_26); + StorageDead(_25); + _29 = copy (((_28 as Some).0: (usize, &T)).0: usize); + _30 = copy (((_28 as Some).0: (usize, &T)).1: &T); StorageLive(_31); - _31 = (copy _29, copy _28); - _32 = Option::<(usize, &T)>::Some(move _31); - StorageDead(_31); - StorageDead(_30); - StorageDead(_29); - _33 = copy (((_32 as Some).0: (usize, &T)).0: usize); - _34 = copy (((_32 as Some).0: (usize, &T)).1: &T); - StorageLive(_35); - _35 = &_2; - StorageLive(_36); - _36 = (copy _33, copy _34); - _37 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _35, move _36) -> [return: bb15, unwind unreachable]; + _31 = &_2; + StorageLive(_32); + _32 = (copy _29, copy _30); + _33 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _31, move _32) -> [return: bb15, unwind unreachable]; } bb15: { - StorageDead(_36); - StorageDead(_35); StorageDead(_32); + StorageDead(_31); + StorageDead(_28); goto -> bb4; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir index 42aa152ec99..28b12cdf367 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.enumerated_loop.PreCodegen.after.panic-unwind.mir @@ -4,22 +4,22 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _11: std::slice::Iter<'_, T>; + let mut _10: std::slice::Iter<'_, T>; + let mut _11: std::iter::Enumerate<std::slice::Iter<'_, T>>; let mut _12: std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _13: std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _14: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>; - let mut _15: std::option::Option<(usize, &T)>; - let mut _16: isize; - let mut _19: &impl Fn(usize, &T); - let mut _20: (usize, &T); - let _21: (); + let mut _13: &mut std::iter::Enumerate<std::slice::Iter<'_, T>>; + let mut _14: std::option::Option<(usize, &T)>; + let mut _15: isize; + let mut _18: &impl Fn(usize, &T); + let mut _19: (usize, &T); + let _20: (); scope 1 { - debug iter => _13; - let _17: usize; - let _18: &T; + debug iter => _12; + let _16: usize; + let _17: &T; scope 2 { - debug i => _17; - debug x => _18; + debug i => _16; + debug x => _17; } } scope 3 (inlined core::slice::<impl [T]>::iter) { @@ -27,7 +27,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { let _3: usize; let mut _7: *mut T; let mut _8: *mut T; - let mut _10: *const T; scope 5 { let _6: std::ptr::NonNull<T>; scope 6 { @@ -62,9 +61,10 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb0: { - StorageLive(_11); + StorageLive(_10); StorageLive(_3); StorageLive(_6); + StorageLive(_9); StorageLive(_4); _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); @@ -72,7 +72,6 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { _5 = copy _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: copy _5 }; StorageDead(_5); - StorageLive(_9); switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -93,33 +92,30 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb3: { - StorageLive(_10); - _10 = copy _9; - _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _10, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_10); - StorageDead(_9); + _10 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _9, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_4); + StorageDead(_9); StorageDead(_6); StorageDead(_3); - _12 = Enumerate::<std::slice::Iter<'_, T>> { iter: copy _11, count: const 0_usize }; - StorageDead(_11); - StorageLive(_13); - _13 = copy _12; + _11 = Enumerate::<std::slice::Iter<'_, T>> { iter: copy _10, count: const 0_usize }; + StorageDead(_10); + StorageLive(_12); + _12 = copy _11; goto -> bb4; } bb4: { - _14 = &mut _13; - _15 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _14) -> [return: bb5, unwind: bb11]; + _13 = &mut _12; + _14 = <Enumerate<std::slice::Iter<'_, T>> as Iterator>::next(move _13) -> [return: bb5, unwind: bb11]; } bb5: { - _16 = discriminant(_15); - switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; + _15 = discriminant(_14); + switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_13); + StorageDead(_12); drop(_2) -> [return: bb7, unwind continue]; } @@ -128,18 +124,18 @@ fn enumerated_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { } bb8: { - _17 = copy (((_15 as Some).0: (usize, &T)).0: usize); - _18 = copy (((_15 as Some).0: (usize, &T)).1: &T); + _16 = copy (((_14 as Some).0: (usize, &T)).0: usize); + _17 = copy (((_14 as Some).0: (usize, &T)).1: &T); + StorageLive(_18); + _18 = &_2; StorageLive(_19); - _19 = &_2; - StorageLive(_20); - _20 = copy ((_15 as Some).0: (usize, &T)); - _21 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _19, move _20) -> [return: bb9, unwind: bb11]; + _19 = copy ((_14 as Some).0: (usize, &T)); + _20 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _18, move _19) -> [return: bb9, unwind: bb11]; } bb9: { - StorageDead(_20); StorageDead(_19); + StorageDead(_18); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir index 0d65640ec9b..4d0e3548e7d 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-abort.mir @@ -4,31 +4,29 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _11: std::ptr::NonNull<T>; - let mut _12: *const T; - let mut _26: std::option::Option<&T>; - let mut _28: &impl Fn(&T); - let mut _29: (&T,); - let _30: (); + let mut _22: std::option::Option<&T>; + let mut _24: &impl Fn(&T); + let mut _25: (&T,); + let _26: (); scope 1 { - debug ((iter: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _11; - debug ((iter: std::slice::Iter<'_, T>).1: *const T) => _12; + debug ((iter: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _6; + debug ((iter: std::slice::Iter<'_, T>).1: *const T) => _9; debug ((iter: std::slice::Iter<'_, T>).2: std::marker::PhantomData<&T>) => const ZeroSized: PhantomData<&T>; - let _27: &T; + let _23: &T; scope 2 { - debug x => _27; + debug x => _23; } scope 16 (inlined <std::slice::Iter<'_, T> as Iterator>::next) { - let _13: std::ptr::NonNull<T>; - let _15: std::ptr::NonNull<T>; - let mut _18: bool; - let mut _21: std::ptr::NonNull<T>; - let mut _23: usize; - let _25: &T; + let mut _6: std::ptr::NonNull<T>; + let _10: std::ptr::NonNull<T>; + let _12: std::ptr::NonNull<T>; + let mut _15: bool; + let mut _19: usize; + let _21: &T; scope 17 { - let _14: *const T; + let _11: *const T; scope 18 { - let _22: usize; + let _18: usize; scope 19 { scope 22 (inlined #[track_caller] core::num::<impl usize>::unchecked_sub) { scope 23 (inlined core::ub_checks::check_language_ub) { @@ -44,21 +42,21 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } scope 26 (inlined <NonNull<T> as PartialEq>::eq) { - let mut _16: *mut T; - let mut _17: *mut T; + let mut _13: *mut T; + let mut _14: *mut T; scope 27 (inlined NonNull::<T>::as_ptr) { } scope 28 (inlined NonNull::<T>::as_ptr) { } } scope 29 (inlined NonNull::<T>::add) { - let mut _19: *const T; - let mut _20: *const T; + let mut _16: *const T; + let mut _17: *const T; scope 30 (inlined NonNull::<T>::as_ptr) { } } scope 31 (inlined NonNull::<T>::as_ref::<'_>) { - let _24: *const T; + let _20: *const T; scope 32 (inlined NonNull::<T>::as_ptr) { } scope 33 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) { @@ -73,9 +71,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { let _3: usize; let mut _7: *mut T; let mut _8: *mut T; - let mut _10: *const T; scope 5 { - let _6: std::ptr::NonNull<T>; scope 6 { let _9: *const T; scope 7 { @@ -112,7 +108,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _5 = copy _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: copy _5 }; StorageDead(_5); - StorageLive(_9); switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -133,88 +128,77 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb3: { - _10 = copy _9; - StorageDead(_9); StorageDead(_4); StorageDead(_3); - StorageLive(_11); - StorageLive(_12); - _11 = copy _6; - _12 = copy _10; goto -> bb4; } bb4: { - StorageLive(_26); - StorageLive(_13); - StorageLive(_14); StorageLive(_22); - StorageLive(_23); - StorageLive(_15); - StorageLive(_25); - _13 = copy _11; - _14 = copy _12; + StorageLive(_10); + StorageLive(_11); + StorageLive(_18); + StorageLive(_19); + StorageLive(_12); + StorageLive(_21); + _10 = copy _6; + _11 = copy _9; switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8]; } bb5: { - StorageLive(_18); - _15 = copy _14 as std::ptr::NonNull<T> (Transmute); - StorageLive(_16); - _16 = copy _13 as *mut T (Transmute); - StorageLive(_17); - _17 = copy _15 as *mut T (Transmute); - _18 = Eq(copy _16, copy _17); - StorageDead(_17); - StorageDead(_16); - switchInt(move _18) -> [0: bb6, otherwise: bb7]; + StorageLive(_15); + _12 = copy _11 as std::ptr::NonNull<T> (Transmute); + StorageLive(_13); + _13 = copy _10 as *mut T (Transmute); + StorageLive(_14); + _14 = copy _12 as *mut T (Transmute); + _15 = Eq(copy _13, copy _14); + StorageDead(_14); + StorageDead(_13); + switchInt(move _15) -> [0: bb6, otherwise: bb7]; } bb6: { - StorageDead(_18); - StorageLive(_21); - StorageLive(_20); - StorageLive(_19); - _19 = copy _13 as *const T (Transmute); - _20 = Offset(copy _19, const 1_usize); - StorageDead(_19); - _21 = NonNull::<T> { pointer: copy _20 }; - StorageDead(_20); - _11 = move _21; - StorageDead(_21); + StorageDead(_15); + StorageLive(_17); + StorageLive(_16); + _16 = copy _10 as *const T (Transmute); + _17 = Offset(copy _16, const 1_usize); + StorageDead(_16); + _6 = NonNull::<T> { pointer: copy _17 }; + StorageDead(_17); goto -> bb13; } bb7: { - StorageDead(_18); - StorageDead(_25); StorageDead(_15); - StorageDead(_23); - StorageDead(_22); - StorageDead(_14); - StorageDead(_13); + StorageDead(_21); + StorageDead(_12); + StorageDead(_19); + StorageDead(_18); + StorageDead(_11); + StorageDead(_10); goto -> bb10; } bb8: { - _22 = copy _14 as usize (Transmute); - switchInt(copy _22) -> [0: bb9, otherwise: bb12]; + _18 = copy _11 as usize (Transmute); + switchInt(copy _18) -> [0: bb9, otherwise: bb12]; } bb9: { - StorageDead(_25); - StorageDead(_15); - StorageDead(_23); - StorageDead(_22); - StorageDead(_14); - StorageDead(_13); + StorageDead(_21); + StorageDead(_12); + StorageDead(_19); + StorageDead(_18); + StorageDead(_11); + StorageDead(_10); goto -> bb10; } bb10: { - StorageDead(_26); - StorageDead(_11); - StorageDead(_12); + StorageDead(_22); drop(_2) -> [return: bb11, unwind unreachable]; } @@ -223,35 +207,35 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb12: { - _23 = SubUnchecked(copy _22, const 1_usize); - _12 = copy _23 as *const T (Transmute); + _19 = SubUnchecked(copy _18, const 1_usize); + _9 = copy _19 as *const T (Transmute); goto -> bb13; } bb13: { + StorageLive(_20); + _20 = copy _10 as *const T (Transmute); + _21 = &(*_20); + StorageDead(_20); + _22 = Option::<&T>::Some(copy _21); + StorageDead(_21); + StorageDead(_12); + StorageDead(_19); + StorageDead(_18); + StorageDead(_11); + StorageDead(_10); + _23 = copy ((_22 as Some).0: &T); StorageLive(_24); - _24 = copy _13 as *const T (Transmute); - _25 = &(*_24); - StorageDead(_24); - _26 = Option::<&T>::Some(copy _25); - StorageDead(_25); - StorageDead(_15); - StorageDead(_23); - StorageDead(_22); - StorageDead(_14); - StorageDead(_13); - _27 = copy ((_26 as Some).0: &T); - StorageLive(_28); - _28 = &_2; - StorageLive(_29); - _29 = (copy _27,); - _30 = <impl Fn(&T) as Fn<(&T,)>>::call(move _28, move _29) -> [return: bb14, unwind unreachable]; + _24 = &_2; + StorageLive(_25); + _25 = (copy _23,); + _26 = <impl Fn(&T) as Fn<(&T,)>>::call(move _24, move _25) -> [return: bb14, unwind unreachable]; } bb14: { - StorageDead(_29); - StorageDead(_28); - StorageDead(_26); + StorageDead(_25); + StorageDead(_24); + StorageDead(_22); goto -> bb4; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir index 02efb193474..2b5d8c27d71 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.forward_loop.PreCodegen.after.panic-unwind.mir @@ -4,31 +4,29 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _11: std::ptr::NonNull<T>; - let mut _12: *const T; - let mut _26: std::option::Option<&T>; - let mut _28: &impl Fn(&T); - let mut _29: (&T,); - let _30: (); + let mut _22: std::option::Option<&T>; + let mut _24: &impl Fn(&T); + let mut _25: (&T,); + let _26: (); scope 1 { - debug ((iter: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _11; - debug ((iter: std::slice::Iter<'_, T>).1: *const T) => _12; + debug ((iter: std::slice::Iter<'_, T>).0: std::ptr::NonNull<T>) => _6; + debug ((iter: std::slice::Iter<'_, T>).1: *const T) => _9; debug ((iter: std::slice::Iter<'_, T>).2: std::marker::PhantomData<&T>) => const ZeroSized: PhantomData<&T>; - let _27: &T; + let _23: &T; scope 2 { - debug x => _27; + debug x => _23; } scope 16 (inlined <std::slice::Iter<'_, T> as Iterator>::next) { - let _13: std::ptr::NonNull<T>; - let _15: std::ptr::NonNull<T>; - let mut _18: bool; - let mut _21: std::ptr::NonNull<T>; - let mut _23: usize; - let _25: &T; + let mut _6: std::ptr::NonNull<T>; + let _10: std::ptr::NonNull<T>; + let _12: std::ptr::NonNull<T>; + let mut _15: bool; + let mut _19: usize; + let _21: &T; scope 17 { - let _14: *const T; + let _11: *const T; scope 18 { - let _22: usize; + let _18: usize; scope 19 { scope 22 (inlined #[track_caller] core::num::<impl usize>::unchecked_sub) { scope 23 (inlined core::ub_checks::check_language_ub) { @@ -44,21 +42,21 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } } scope 26 (inlined <NonNull<T> as PartialEq>::eq) { - let mut _16: *mut T; - let mut _17: *mut T; + let mut _13: *mut T; + let mut _14: *mut T; scope 27 (inlined NonNull::<T>::as_ptr) { } scope 28 (inlined NonNull::<T>::as_ptr) { } } scope 29 (inlined NonNull::<T>::add) { - let mut _19: *const T; - let mut _20: *const T; + let mut _16: *const T; + let mut _17: *const T; scope 30 (inlined NonNull::<T>::as_ptr) { } } scope 31 (inlined NonNull::<T>::as_ref::<'_>) { - let _24: *const T; + let _20: *const T; scope 32 (inlined NonNull::<T>::as_ptr) { } scope 33 (inlined std::ptr::mut_ptr::<impl *mut T>::cast_const) { @@ -73,9 +71,7 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { let _3: usize; let mut _7: *mut T; let mut _8: *mut T; - let mut _10: *const T; scope 5 { - let _6: std::ptr::NonNull<T>; scope 6 { let _9: *const T; scope 7 { @@ -112,7 +108,6 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { _5 = copy _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: copy _5 }; StorageDead(_5); - StorageLive(_9); switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -133,88 +128,77 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb3: { - _10 = copy _9; - StorageDead(_9); StorageDead(_4); StorageDead(_3); - StorageLive(_11); - StorageLive(_12); - _11 = copy _6; - _12 = copy _10; goto -> bb4; } bb4: { - StorageLive(_26); - StorageLive(_13); - StorageLive(_14); StorageLive(_22); - StorageLive(_23); - StorageLive(_15); - StorageLive(_25); - _13 = copy _11; - _14 = copy _12; + StorageLive(_10); + StorageLive(_11); + StorageLive(_18); + StorageLive(_19); + StorageLive(_12); + StorageLive(_21); + _10 = copy _6; + _11 = copy _9; switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb5, otherwise: bb8]; } bb5: { - StorageLive(_18); - _15 = copy _14 as std::ptr::NonNull<T> (Transmute); - StorageLive(_16); - _16 = copy _13 as *mut T (Transmute); - StorageLive(_17); - _17 = copy _15 as *mut T (Transmute); - _18 = Eq(copy _16, copy _17); - StorageDead(_17); - StorageDead(_16); - switchInt(move _18) -> [0: bb6, otherwise: bb7]; + StorageLive(_15); + _12 = copy _11 as std::ptr::NonNull<T> (Transmute); + StorageLive(_13); + _13 = copy _10 as *mut T (Transmute); + StorageLive(_14); + _14 = copy _12 as *mut T (Transmute); + _15 = Eq(copy _13, copy _14); + StorageDead(_14); + StorageDead(_13); + switchInt(move _15) -> [0: bb6, otherwise: bb7]; } bb6: { - StorageDead(_18); - StorageLive(_21); - StorageLive(_20); - StorageLive(_19); - _19 = copy _13 as *const T (Transmute); - _20 = Offset(copy _19, const 1_usize); - StorageDead(_19); - _21 = NonNull::<T> { pointer: copy _20 }; - StorageDead(_20); - _11 = move _21; - StorageDead(_21); + StorageDead(_15); + StorageLive(_17); + StorageLive(_16); + _16 = copy _10 as *const T (Transmute); + _17 = Offset(copy _16, const 1_usize); + StorageDead(_16); + _6 = NonNull::<T> { pointer: copy _17 }; + StorageDead(_17); goto -> bb13; } bb7: { - StorageDead(_18); - StorageDead(_25); StorageDead(_15); - StorageDead(_23); - StorageDead(_22); - StorageDead(_14); - StorageDead(_13); + StorageDead(_21); + StorageDead(_12); + StorageDead(_19); + StorageDead(_18); + StorageDead(_11); + StorageDead(_10); goto -> bb10; } bb8: { - _22 = copy _14 as usize (Transmute); - switchInt(copy _22) -> [0: bb9, otherwise: bb12]; + _18 = copy _11 as usize (Transmute); + switchInt(copy _18) -> [0: bb9, otherwise: bb12]; } bb9: { - StorageDead(_25); - StorageDead(_15); - StorageDead(_23); - StorageDead(_22); - StorageDead(_14); - StorageDead(_13); + StorageDead(_21); + StorageDead(_12); + StorageDead(_19); + StorageDead(_18); + StorageDead(_11); + StorageDead(_10); goto -> bb10; } bb10: { - StorageDead(_26); - StorageDead(_11); - StorageDead(_12); + StorageDead(_22); drop(_2) -> [return: bb11, unwind continue]; } @@ -223,35 +207,35 @@ fn forward_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb12: { - _23 = SubUnchecked(copy _22, const 1_usize); - _12 = copy _23 as *const T (Transmute); + _19 = SubUnchecked(copy _18, const 1_usize); + _9 = copy _19 as *const T (Transmute); goto -> bb13; } bb13: { + StorageLive(_20); + _20 = copy _10 as *const T (Transmute); + _21 = &(*_20); + StorageDead(_20); + _22 = Option::<&T>::Some(copy _21); + StorageDead(_21); + StorageDead(_12); + StorageDead(_19); + StorageDead(_18); + StorageDead(_11); + StorageDead(_10); + _23 = copy ((_22 as Some).0: &T); StorageLive(_24); - _24 = copy _13 as *const T (Transmute); - _25 = &(*_24); - StorageDead(_24); - _26 = Option::<&T>::Some(copy _25); - StorageDead(_25); - StorageDead(_15); - StorageDead(_23); - StorageDead(_22); - StorageDead(_14); - StorageDead(_13); - _27 = copy ((_26 as Some).0: &T); - StorageLive(_28); - _28 = &_2; - StorageLive(_29); - _29 = (copy _27,); - _30 = <impl Fn(&T) as Fn<(&T,)>>::call(move _28, move _29) -> [return: bb14, unwind: bb15]; + _24 = &_2; + StorageLive(_25); + _25 = (copy _23,); + _26 = <impl Fn(&T) as Fn<(&T,)>>::call(move _24, move _25) -> [return: bb14, unwind: bb15]; } bb14: { - StorageDead(_29); - StorageDead(_28); - StorageDead(_26); + StorageDead(_25); + StorageDead(_24); + StorageDead(_22); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir index 41e273151ec..14537599071 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-abort.mir @@ -5,28 +5,27 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug f => _2; let mut _0: (); let mut _3: usize; - let mut _4: usize; - let mut _9: std::option::Option<usize>; - let mut _11: bool; - let mut _13: &impl Fn(usize, &T); - let mut _14: (usize, &T); - let _15: (); + let mut _8: std::option::Option<usize>; + let mut _10: bool; + let mut _12: &impl Fn(usize, &T); + let mut _13: (usize, &T); + let _14: (); scope 1 { debug ((iter: std::ops::Range<usize>).0: usize) => _4; debug ((iter: std::ops::Range<usize>).1: usize) => _3; - let _10: usize; + let _9: usize; scope 2 { - debug i => _10; - let _12: &T; + debug i => _9; + let _11: &T; scope 3 { - debug x => _12; + debug x => _11; } } scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<usize>>::next) { scope 6 (inlined <std::ops::Range<usize> as iter::range::RangeIteratorImpl>::spec_next) { + let mut _4: usize; let mut _6: bool; let _7: usize; - let mut _8: usize; scope 7 { scope 9 (inlined <usize as Step>::forward_unchecked) { scope 10 (inlined #[track_caller] core::num::<impl usize>::unchecked_add) { @@ -48,13 +47,12 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { bb0: { _3 = PtrMetadata(copy _1); - StorageLive(_4); _4 = const 0_usize; goto -> bb1; } bb1: { - StorageLive(_9); + StorageLive(_8); StorageLive(_6); StorageLive(_5); _5 = copy _4; @@ -65,8 +63,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { bb2: { StorageDead(_6); - StorageDead(_9); - StorageDead(_4); + StorageDead(_8); drop(_2) -> [return: bb3, unwind unreachable]; } @@ -76,30 +73,27 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { bb4: { _7 = copy _4; - StorageLive(_8); - _8 = AddUnchecked(copy _7, const 1_usize); - _4 = move _8; - StorageDead(_8); - _9 = Option::<usize>::Some(copy _7); + _4 = AddUnchecked(copy _7, const 1_usize); + _8 = Option::<usize>::Some(copy _7); StorageDead(_6); - _10 = copy ((_9 as Some).0: usize); - _11 = Lt(copy _10, copy _3); - assert(move _11, "index out of bounds: the length is {} but the index is {}", copy _3, copy _10) -> [success: bb5, unwind unreachable]; + _9 = copy ((_8 as Some).0: usize); + _10 = Lt(copy _9, copy _3); + assert(move _10, "index out of bounds: the length is {} but the index is {}", copy _3, copy _9) -> [success: bb5, unwind unreachable]; } bb5: { - _12 = &(*_1)[_10]; + _11 = &(*_1)[_9]; + StorageLive(_12); + _12 = &_2; StorageLive(_13); - _13 = &_2; - StorageLive(_14); - _14 = (copy _10, copy _12); - _15 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _13, move _14) -> [return: bb6, unwind unreachable]; + _13 = (copy _9, copy _11); + _14 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _12, move _13) -> [return: bb6, unwind unreachable]; } bb6: { - StorageDead(_14); StorageDead(_13); - StorageDead(_9); + StorageDead(_12); + StorageDead(_8); goto -> bb1; } } diff --git a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir index ec781c1480c..8e573ef488f 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.range_loop.PreCodegen.after.panic-unwind.mir @@ -5,28 +5,27 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { debug f => _2; let mut _0: (); let mut _3: usize; - let mut _4: usize; - let mut _9: std::option::Option<usize>; - let mut _11: bool; - let mut _13: &impl Fn(usize, &T); - let mut _14: (usize, &T); - let _15: (); + let mut _8: std::option::Option<usize>; + let mut _10: bool; + let mut _12: &impl Fn(usize, &T); + let mut _13: (usize, &T); + let _14: (); scope 1 { debug ((iter: std::ops::Range<usize>).0: usize) => _4; debug ((iter: std::ops::Range<usize>).1: usize) => _3; - let _10: usize; + let _9: usize; scope 2 { - debug i => _10; - let _12: &T; + debug i => _9; + let _11: &T; scope 3 { - debug x => _12; + debug x => _11; } } scope 5 (inlined iter::range::<impl Iterator for std::ops::Range<usize>>::next) { scope 6 (inlined <std::ops::Range<usize> as iter::range::RangeIteratorImpl>::spec_next) { + let mut _4: usize; let mut _6: bool; let _7: usize; - let mut _8: usize; scope 7 { scope 9 (inlined <usize as Step>::forward_unchecked) { scope 10 (inlined #[track_caller] core::num::<impl usize>::unchecked_add) { @@ -48,13 +47,12 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { bb0: { _3 = PtrMetadata(copy _1); - StorageLive(_4); _4 = const 0_usize; goto -> bb1; } bb1: { - StorageLive(_9); + StorageLive(_8); StorageLive(_6); StorageLive(_5); _5 = copy _4; @@ -65,8 +63,7 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { bb2: { StorageDead(_6); - StorageDead(_9); - StorageDead(_4); + StorageDead(_8); drop(_2) -> [return: bb3, unwind continue]; } @@ -76,30 +73,27 @@ fn range_loop(_1: &[T], _2: impl Fn(usize, &T)) -> () { bb4: { _7 = copy _4; - StorageLive(_8); - _8 = AddUnchecked(copy _7, const 1_usize); - _4 = move _8; - StorageDead(_8); - _9 = Option::<usize>::Some(copy _7); + _4 = AddUnchecked(copy _7, const 1_usize); + _8 = Option::<usize>::Some(copy _7); StorageDead(_6); - _10 = copy ((_9 as Some).0: usize); - _11 = Lt(copy _10, copy _3); - assert(move _11, "index out of bounds: the length is {} but the index is {}", copy _3, copy _10) -> [success: bb5, unwind: bb7]; + _9 = copy ((_8 as Some).0: usize); + _10 = Lt(copy _9, copy _3); + assert(move _10, "index out of bounds: the length is {} but the index is {}", copy _3, copy _9) -> [success: bb5, unwind: bb7]; } bb5: { - _12 = &(*_1)[_10]; + _11 = &(*_1)[_9]; + StorageLive(_12); + _12 = &_2; StorageLive(_13); - _13 = &_2; - StorageLive(_14); - _14 = (copy _10, copy _12); - _15 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _13, move _14) -> [return: bb6, unwind: bb7]; + _13 = (copy _9, copy _11); + _14 = <impl Fn(usize, &T) as Fn<(usize, &T)>>::call(move _12, move _13) -> [return: bb6, unwind: bb7]; } bb6: { - StorageDead(_14); StorageDead(_13); - StorageDead(_9); + StorageDead(_12); + StorageDead(_8); goto -> bb1; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir index ee638be7d7a..0adf268d766 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-abort.mir @@ -4,22 +4,22 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _11: std::slice::Iter<'_, T>; + let mut _10: std::slice::Iter<'_, T>; + let mut _11: std::iter::Rev<std::slice::Iter<'_, T>>; let mut _12: std::iter::Rev<std::slice::Iter<'_, T>>; - let mut _13: std::iter::Rev<std::slice::Iter<'_, T>>; - let mut _15: std::option::Option<&T>; - let mut _16: isize; - let mut _18: &impl Fn(&T); - let mut _19: (&T,); - let _20: (); + let mut _14: std::option::Option<&T>; + let mut _15: isize; + let mut _17: &impl Fn(&T); + let mut _18: (&T,); + let _19: (); scope 1 { - debug iter => _13; - let _17: &T; + debug iter => _12; + let _16: &T; scope 2 { - debug x => _17; + debug x => _16; } scope 18 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) { - let mut _14: &mut std::slice::Iter<'_, T>; + let mut _13: &mut std::slice::Iter<'_, T>; } } scope 3 (inlined core::slice::<impl [T]>::iter) { @@ -27,7 +27,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { let _3: usize; let mut _7: *mut T; let mut _8: *mut T; - let mut _10: *const T; scope 5 { let _6: std::ptr::NonNull<T>; scope 6 { @@ -62,9 +61,10 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb0: { - StorageLive(_11); + StorageLive(_10); StorageLive(_3); StorageLive(_6); + StorageLive(_9); StorageLive(_4); _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); @@ -72,7 +72,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _5 = copy _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: copy _5 }; StorageDead(_5); - StorageLive(_9); switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -93,37 +92,34 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb3: { - StorageLive(_10); - _10 = copy _9; - _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _10, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_10); - StorageDead(_9); + _10 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _9, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_4); + StorageDead(_9); StorageDead(_6); StorageDead(_3); - _12 = Rev::<std::slice::Iter<'_, T>> { iter: copy _11 }; - StorageDead(_11); - StorageLive(_13); - _13 = copy _12; + _11 = Rev::<std::slice::Iter<'_, T>> { iter: copy _10 }; + StorageDead(_10); + StorageLive(_12); + _12 = copy _11; goto -> bb4; } bb4: { - StorageLive(_15); StorageLive(_14); - _14 = &mut (_13.0: std::slice::Iter<'_, T>); - _15 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _14) -> [return: bb5, unwind unreachable]; + StorageLive(_13); + _13 = &mut (_12.0: std::slice::Iter<'_, T>); + _14 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _13) -> [return: bb5, unwind unreachable]; } bb5: { - StorageDead(_14); - _16 = discriminant(_15); - switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageDead(_13); + _15 = discriminant(_14); + switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_15); - StorageDead(_13); + StorageDead(_14); + StorageDead(_12); drop(_2) -> [return: bb7, unwind unreachable]; } @@ -132,18 +128,18 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb8: { - _17 = copy ((_15 as Some).0: &T); + _16 = copy ((_14 as Some).0: &T); + StorageLive(_17); + _17 = &_2; StorageLive(_18); - _18 = &_2; - StorageLive(_19); - _19 = (copy _17,); - _20 = <impl Fn(&T) as Fn<(&T,)>>::call(move _18, move _19) -> [return: bb9, unwind unreachable]; + _18 = (copy _16,); + _19 = <impl Fn(&T) as Fn<(&T,)>>::call(move _17, move _18) -> [return: bb9, unwind unreachable]; } bb9: { - StorageDead(_19); StorageDead(_18); - StorageDead(_15); + StorageDead(_17); + StorageDead(_14); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir index aee29d4d4fe..cb0d640d445 100644 --- a/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_iter.reverse_loop.PreCodegen.after.panic-unwind.mir @@ -4,22 +4,22 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { debug slice => _1; debug f => _2; let mut _0: (); - let mut _11: std::slice::Iter<'_, T>; + let mut _10: std::slice::Iter<'_, T>; + let mut _11: std::iter::Rev<std::slice::Iter<'_, T>>; let mut _12: std::iter::Rev<std::slice::Iter<'_, T>>; - let mut _13: std::iter::Rev<std::slice::Iter<'_, T>>; - let mut _15: std::option::Option<&T>; - let mut _16: isize; - let mut _18: &impl Fn(&T); - let mut _19: (&T,); - let _20: (); + let mut _14: std::option::Option<&T>; + let mut _15: isize; + let mut _17: &impl Fn(&T); + let mut _18: (&T,); + let _19: (); scope 1 { - debug iter => _13; - let _17: &T; + debug iter => _12; + let _16: &T; scope 2 { - debug x => _17; + debug x => _16; } scope 18 (inlined <Rev<std::slice::Iter<'_, T>> as Iterator>::next) { - let mut _14: &mut std::slice::Iter<'_, T>; + let mut _13: &mut std::slice::Iter<'_, T>; } } scope 3 (inlined core::slice::<impl [T]>::iter) { @@ -27,7 +27,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { let _3: usize; let mut _7: *mut T; let mut _8: *mut T; - let mut _10: *const T; scope 5 { let _6: std::ptr::NonNull<T>; scope 6 { @@ -62,9 +61,10 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb0: { - StorageLive(_11); + StorageLive(_10); StorageLive(_3); StorageLive(_6); + StorageLive(_9); StorageLive(_4); _3 = PtrMetadata(copy _1); _4 = &raw const (*_1); @@ -72,7 +72,6 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { _5 = copy _4 as *const T (PtrToPtr); _6 = NonNull::<T> { pointer: copy _5 }; StorageDead(_5); - StorageLive(_9); switchInt(const <T as std::mem::SizedTypeProperties>::IS_ZST) -> [0: bb1, otherwise: bb2]; } @@ -93,37 +92,34 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb3: { - StorageLive(_10); - _10 = copy _9; - _11 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _10, _marker: const ZeroSized: PhantomData<&T> }; - StorageDead(_10); - StorageDead(_9); + _10 = std::slice::Iter::<'_, T> { ptr: copy _6, end_or_len: copy _9, _marker: const ZeroSized: PhantomData<&T> }; StorageDead(_4); + StorageDead(_9); StorageDead(_6); StorageDead(_3); - _12 = Rev::<std::slice::Iter<'_, T>> { iter: copy _11 }; - StorageDead(_11); - StorageLive(_13); - _13 = copy _12; + _11 = Rev::<std::slice::Iter<'_, T>> { iter: copy _10 }; + StorageDead(_10); + StorageLive(_12); + _12 = copy _11; goto -> bb4; } bb4: { - StorageLive(_15); StorageLive(_14); - _14 = &mut (_13.0: std::slice::Iter<'_, T>); - _15 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _14) -> [return: bb5, unwind: bb11]; + StorageLive(_13); + _13 = &mut (_12.0: std::slice::Iter<'_, T>); + _14 = <std::slice::Iter<'_, T> as DoubleEndedIterator>::next_back(move _13) -> [return: bb5, unwind: bb11]; } bb5: { - StorageDead(_14); - _16 = discriminant(_15); - switchInt(move _16) -> [0: bb6, 1: bb8, otherwise: bb10]; + StorageDead(_13); + _15 = discriminant(_14); + switchInt(move _15) -> [0: bb6, 1: bb8, otherwise: bb10]; } bb6: { - StorageDead(_15); - StorageDead(_13); + StorageDead(_14); + StorageDead(_12); drop(_2) -> [return: bb7, unwind continue]; } @@ -132,18 +128,18 @@ fn reverse_loop(_1: &[T], _2: impl Fn(&T)) -> () { } bb8: { - _17 = copy ((_15 as Some).0: &T); + _16 = copy ((_14 as Some).0: &T); + StorageLive(_17); + _17 = &_2; StorageLive(_18); - _18 = &_2; - StorageLive(_19); - _19 = (copy _17,); - _20 = <impl Fn(&T) as Fn<(&T,)>>::call(move _18, move _19) -> [return: bb9, unwind: bb11]; + _18 = (copy _16,); + _19 = <impl Fn(&T) as Fn<(&T,)>>::call(move _17, move _18) -> [return: bb9, unwind: bb11]; } bb9: { - StorageDead(_19); StorageDead(_18); - StorageDead(_15); + StorageDead(_17); + StorageDead(_14); goto -> bb4; } diff --git a/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir index c4d0e318b58..29bfe962974 100644 --- a/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/tuple_ord.demo_ge_partial.PreCodegen.after.mir @@ -7,7 +7,6 @@ fn demo_ge_partial(_1: &(f32, f32), _2: &(f32, f32)) -> bool { scope 1 (inlined std::cmp::impls::<impl PartialOrd for &(f32, f32)>::ge) { scope 2 (inlined core::tuple::<impl PartialOrd for (f32, f32)>::ge) { let mut _7: std::ops::ControlFlow<bool>; - let _8: bool; scope 3 { } scope 4 (inlined std::cmp::impls::<impl PartialOrd for f32>::__chaining_ge) { @@ -19,8 +18,8 @@ fn demo_ge_partial(_1: &(f32, f32), _2: &(f32, f32)) -> bool { } } scope 6 (inlined std::cmp::impls::<impl PartialOrd for f32>::ge) { + let mut _8: f32; let mut _9: f32; - let mut _10: f32; } } } @@ -44,10 +43,7 @@ fn demo_ge_partial(_1: &(f32, f32), _2: &(f32, f32)) -> bool { StorageDead(_5); StorageDead(_4); StorageDead(_3); - StorageLive(_8); - _8 = copy ((_7 as Break).0: bool); - _0 = copy _8; - StorageDead(_8); + _0 = copy ((_7 as Break).0: bool); goto -> bb3; } @@ -55,13 +51,13 @@ fn demo_ge_partial(_1: &(f32, f32), _2: &(f32, f32)) -> bool { StorageDead(_5); StorageDead(_4); StorageDead(_3); + StorageLive(_8); + _8 = copy ((*_1).1: f32); StorageLive(_9); - _9 = copy ((*_1).1: f32); - StorageLive(_10); - _10 = copy ((*_2).1: f32); - _0 = Ge(move _9, move _10); - StorageDead(_10); + _9 = copy ((*_2).1: f32); + _0 = Ge(move _8, move _9); StorageDead(_9); + StorageDead(_8); goto -> bb3; } diff --git a/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir b/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir index 44df8b27993..7678c92a1f0 100644 --- a/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir +++ b/tests/mir-opt/pre-codegen/tuple_ord.demo_le_total.PreCodegen.after.mir @@ -7,7 +7,6 @@ fn demo_le_total(_1: &(u16, i16), _2: &(u16, i16)) -> bool { scope 1 (inlined std::cmp::impls::<impl PartialOrd for &(u16, i16)>::le) { scope 2 (inlined core::tuple::<impl PartialOrd for (u16, i16)>::le) { let mut _7: std::ops::ControlFlow<bool>; - let _8: bool; scope 3 { } scope 4 (inlined std::cmp::impls::<impl PartialOrd for u16>::__chaining_le) { @@ -19,8 +18,8 @@ fn demo_le_total(_1: &(u16, i16), _2: &(u16, i16)) -> bool { } } scope 6 (inlined std::cmp::impls::<impl PartialOrd for i16>::le) { + let mut _8: i16; let mut _9: i16; - let mut _10: i16; } } } @@ -44,10 +43,7 @@ fn demo_le_total(_1: &(u16, i16), _2: &(u16, i16)) -> bool { StorageDead(_5); StorageDead(_4); StorageDead(_3); - StorageLive(_8); - _8 = copy ((_7 as Break).0: bool); - _0 = copy _8; - StorageDead(_8); + _0 = copy ((_7 as Break).0: bool); goto -> bb3; } @@ -55,13 +51,13 @@ fn demo_le_total(_1: &(u16, i16), _2: &(u16, i16)) -> bool { StorageDead(_5); StorageDead(_4); StorageDead(_3); + StorageLive(_8); + _8 = copy ((*_1).1: i16); StorageLive(_9); - _9 = copy ((*_1).1: i16); - StorageLive(_10); - _10 = copy ((*_2).1: i16); - _0 = Le(move _9, move _10); - StorageDead(_10); + _9 = copy ((*_2).1: i16); + _0 = Le(move _8, move _9); StorageDead(_9); + StorageDead(_8); goto -> bb3; } diff --git a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff index 3da795b61f9..375b6096d88 100644 --- a/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff +++ b/tests/mir-opt/reference_prop.debuginfo.ReferencePropagation.diff @@ -17,14 +17,15 @@ let mut _15: std::ops::RangeFull; let mut _16: usize; let mut _17: usize; - let mut _18: bool; - let _23: &&mut u8; - let _24: &mut u8; - let mut _25: debuginfo::T; + let mut _18: usize; + let mut _19: bool; + let _24: &&mut u8; + let _25: &mut u8; + let mut _26: debuginfo::T; scope 1 { debug ref_mut_u8 => _1; let _3: &u8; - let mut _28: &debuginfo::T; + let mut _29: &debuginfo::T; scope 2 { debug field => _3; let _5: &u8; @@ -32,22 +33,22 @@ - debug reborrow => _5; + debug reborrow => _1; let _9: &i32; - let _22: &&&mut u8; - let mut _27: &std::option::Option<i32>; + let _23: &&&mut u8; + let mut _28: &std::option::Option<i32>; scope 4 { debug variant_field => _9; } scope 5 { - debug constant_index => _19; - debug subslice => _20; - debug constant_index_from_end => _21; - let _19: &i32; - let _20: &[i32]; - let _21: &i32; - let mut _26: &[i32; 10]; + debug constant_index => _20; + debug subslice => _21; + debug constant_index_from_end => _22; + let _20: &i32; + let _21: &[i32]; + let _22: &i32; + let mut _27: &[i32; 10]; } scope 6 { - debug multiple_borrow => _22; + debug multiple_borrow => _23; } } } @@ -59,8 +60,8 @@ _2 = const 5_u8; _1 = &mut _2; StorageLive(_3); - _28 = const debuginfo::promoted[2]; - _3 = &((*_28).0: u8); + _29 = const debuginfo::promoted[2]; + _3 = &((*_29).0: u8); - StorageLive(_5); - _5 = &(*_1); - StorageLive(_6); @@ -76,8 +77,8 @@ bb2: { StorageLive(_9); - _27 = const debuginfo::promoted[1]; - _9 = &(((*_27) as Some).0: i32); + _28 = const debuginfo::promoted[1]; + _9 = &(((*_28) as Some).0: i32); - _6 = const (); StorageDead(_9); goto -> bb4; @@ -92,11 +93,11 @@ StorageDead(_7); - StorageDead(_6); - StorageLive(_10); -- StorageLive(_11); + StorageLive(_11); - StorageLive(_12); StorageLive(_13); - _26 = const debuginfo::promoted[0]; - _13 = &(*_26); + _27 = const debuginfo::promoted[0]; + _13 = &(*_27); StorageLive(_15); _15 = RangeFull; - _12 = <[i32; 10] as Index<RangeFull>>::index(move _13, move _15) -> [return: bb5, unwind continue]; @@ -106,28 +107,28 @@ bb5: { StorageDead(_15); StorageDead(_13); -- _11 = &(*_12); -- _16 = Len((*_11)); -+ _16 = Len((*_12)); - _17 = const 3_usize; - _18 = Ge(move _16, move _17); - switchInt(move _18) -> [0: bb7, otherwise: bb6]; + _11 = &(*_12); + _17 = PtrMetadata(copy _11); + _16 = move _17; + _18 = const 3_usize; + _19 = Ge(move _16, move _18); + switchInt(move _19) -> [0: bb7, otherwise: bb6]; } bb6: { - StorageLive(_19); -- _19 = &(*_11)[1 of 3]; -+ _19 = &(*_12)[1 of 3]; StorageLive(_20); -- _20 = &(*_11)[2:-1]; -+ _20 = &(*_12)[2:-1]; +- _20 = &(*_11)[1 of 3]; ++ _20 = &(*_12)[1 of 3]; StorageLive(_21); -- _21 = &(*_11)[-1 of 3]; +- _21 = &(*_11)[2:-1]; ++ _21 = &(*_12)[2:-1]; + StorageLive(_22); +- _22 = &(*_11)[-1 of 3]; - _10 = const (); -+ _21 = &(*_12)[-1 of 3]; ++ _22 = &(*_12)[-1 of 3]; + StorageDead(_22); StorageDead(_21); StorageDead(_20); - StorageDead(_19); goto -> bb8; } @@ -138,21 +139,21 @@ bb8: { - StorageDead(_12); -- StorageDead(_11); + StorageDead(_11); - StorageDead(_10); - StorageLive(_22); StorageLive(_23); StorageLive(_24); StorageLive(_25); - _25 = T(const 6_u8); - _24 = &mut (_25.0: u8); + StorageLive(_26); + _26 = T(const 6_u8); + _25 = &mut (_26.0: u8); + _24 = &_25; _23 = &_24; - _22 = &_23; _0 = const (); + StorageDead(_26); StorageDead(_25); StorageDead(_24); StorageDead(_23); - StorageDead(_22); - StorageDead(_5); StorageDead(_3); StorageDead(_2); diff --git a/tests/run-make/musl-default-linking/rmake.rs b/tests/run-make/musl-default-linking/rmake.rs index 7bb54e2739c..1b30c538b5e 100644 --- a/tests/run-make/musl-default-linking/rmake.rs +++ b/tests/run-make/musl-default-linking/rmake.rs @@ -4,7 +4,7 @@ use run_make_support::{rustc, serde_json}; // Per https://github.com/rust-lang/compiler-team/issues/422, // we should be trying to move these targets to dynamically link // musl libc by default. -//@ needs-llvm-components: aarch64 arm mips powerpc riscv systemz x86 +//@ needs-llvm-components: aarch64 arm mips powerpc x86 static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[ "aarch64-unknown-linux-musl", "arm-unknown-linux-musleabi", @@ -14,16 +14,8 @@ static LEGACY_STATIC_LINKING_TARGETS: &[&'static str] = &[ "armv7-unknown-linux-musleabihf", "i586-unknown-linux-musl", "i686-unknown-linux-musl", - "mips64-unknown-linux-musl", - "mips64-unknown-linux-muslabi64", "mips64el-unknown-linux-muslabi64", - "powerpc-unknown-linux-musl", - "powerpc-unknown-linux-muslspe", - "powerpc64-unknown-linux-musl", "powerpc64le-unknown-linux-musl", - "riscv32gc-unknown-linux-musl", - "s390x-unknown-linux-musl", - "thumbv7neon-unknown-linux-musleabihf", "x86_64-unknown-linux-musl", ]; diff --git a/tests/ui/README.md b/tests/ui/README.md index 66c1bb905a7..3b28ef694dd 100644 --- a/tests/ui/README.md +++ b/tests/ui/README.md @@ -350,6 +350,12 @@ Tests for FFI with C varargs (`va_list`). Tests for detection and handling of cyclic trait dependencies. +## `tests/ui/darwin-objc/`: Darwin Objective-C + +Tests exercising `#![feature(darwin_objc)]`. + +See [Tracking Issue for `darwin_objc` #145496](https://github.com/rust-lang/rust/issues/145496). + ## `tests/ui/dataflow_const_prop/` Contains a single regression test for const prop in `SwitchInt` pass crashing when `ptr2int` transmute is involved. diff --git a/tests/ui/abi/sparcv8plus-llvm19.rs b/tests/ui/abi/sparcv8plus-llvm19.rs deleted file mode 100644 index 3d6d8568b6e..00000000000 --- a/tests/ui/abi/sparcv8plus-llvm19.rs +++ /dev/null @@ -1,42 +0,0 @@ -//@ add-core-stubs -//@ revisions: sparc sparcv8plus sparc_cpu_v9 sparc_feature_v8plus sparc_cpu_v9_feature_v8plus -//@[sparc] compile-flags: --target sparc-unknown-none-elf -//@[sparc] needs-llvm-components: sparc -//@[sparcv8plus] compile-flags: --target sparc-unknown-linux-gnu -//@[sparcv8plus] needs-llvm-components: sparc -//@[sparc_cpu_v9] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9 -//@[sparc_cpu_v9] needs-llvm-components: sparc -//@[sparc_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-feature=+v8plus -//@[sparc_feature_v8plus] needs-llvm-components: sparc -//@[sparc_cpu_v9_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9 -C target-feature=+v8plus -//@[sparc_cpu_v9_feature_v8plus] needs-llvm-components: sparc -//@ exact-llvm-major-version: 19 - -#![crate_type = "rlib"] -#![feature(no_core, rustc_attrs, lang_items)] -#![no_core] - -extern crate minicore; -use minicore::*; - -#[rustc_builtin_macro] -macro_rules! compile_error { - () => {}; -} - -#[cfg(all(not(target_feature = "v8plus"), not(target_feature = "v9")))] -compile_error!("-v8plus,-v9"); -//[sparc]~^ ERROR -v8plus,-v9 - -// FIXME: sparc_cpu_v9 should be in "-v8plus,+v9" group (fixed in LLVM 20) -#[cfg(all(target_feature = "v8plus", target_feature = "v9"))] -compile_error!("+v8plus,+v9"); -//[sparcv8plus,sparc_cpu_v9_feature_v8plus,sparc_cpu_v9]~^ ERROR +v8plus,+v9 - -// FIXME: should be rejected -#[cfg(all(target_feature = "v8plus", not(target_feature = "v9")))] -compile_error!("+v8plus,-v9 (FIXME)"); -//[sparc_feature_v8plus]~^ ERROR +v8plus,-v9 (FIXME) - -#[cfg(all(not(target_feature = "v8plus"), target_feature = "v9"))] -compile_error!("-v8plus,+v9"); diff --git a/tests/ui/abi/sparcv8plus-llvm19.sparc.stderr b/tests/ui/abi/sparcv8plus-llvm19.sparc.stderr deleted file mode 100644 index d3462ae87d3..00000000000 --- a/tests/ui/abi/sparcv8plus-llvm19.sparc.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: -v8plus,-v9 - --> $DIR/sparcv8plus-llvm19.rs:28:1 - | -LL | compile_error!("-v8plus,-v9"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9.stderr b/tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9.stderr deleted file mode 100644 index 9891aec94b8..00000000000 --- a/tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: +v8plus,+v9 - --> $DIR/sparcv8plus-llvm19.rs:33:1 - | -LL | compile_error!("+v8plus,+v9"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9_feature_v8plus.stderr b/tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9_feature_v8plus.stderr deleted file mode 100644 index 9891aec94b8..00000000000 --- a/tests/ui/abi/sparcv8plus-llvm19.sparc_cpu_v9_feature_v8plus.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: +v8plus,+v9 - --> $DIR/sparcv8plus-llvm19.rs:33:1 - | -LL | compile_error!("+v8plus,+v9"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/abi/sparcv8plus-llvm19.sparc_feature_v8plus.stderr b/tests/ui/abi/sparcv8plus-llvm19.sparc_feature_v8plus.stderr deleted file mode 100644 index dbcdb8ed121..00000000000 --- a/tests/ui/abi/sparcv8plus-llvm19.sparc_feature_v8plus.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: +v8plus,-v9 (FIXME) - --> $DIR/sparcv8plus-llvm19.rs:38:1 - | -LL | compile_error!("+v8plus,-v9 (FIXME)"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/abi/sparcv8plus-llvm19.sparcv8plus.stderr b/tests/ui/abi/sparcv8plus-llvm19.sparcv8plus.stderr deleted file mode 100644 index 9891aec94b8..00000000000 --- a/tests/ui/abi/sparcv8plus-llvm19.sparcv8plus.stderr +++ /dev/null @@ -1,8 +0,0 @@ -error: +v8plus,+v9 - --> $DIR/sparcv8plus-llvm19.rs:33:1 - | -LL | compile_error!("+v8plus,+v9"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error - diff --git a/tests/ui/abi/sparcv8plus.rs b/tests/ui/abi/sparcv8plus.rs index 6c17f721838..ba4fb6f7108 100644 --- a/tests/ui/abi/sparcv8plus.rs +++ b/tests/ui/abi/sparcv8plus.rs @@ -10,7 +10,6 @@ //@[sparc_feature_v8plus] needs-llvm-components: sparc //@[sparc_cpu_v9_feature_v8plus] compile-flags: --target sparc-unknown-none-elf -C target-cpu=v9 -C target-feature=+v8plus //@[sparc_cpu_v9_feature_v8plus] needs-llvm-components: sparc -//@ min-llvm-version: 20 #![crate_type = "rlib"] #![feature(no_core, rustc_attrs, lang_items)] diff --git a/tests/ui/abi/sparcv8plus.sparc.stderr b/tests/ui/abi/sparcv8plus.sparc.stderr index e2aa89a9273..e31dbd344d6 100644 --- a/tests/ui/abi/sparcv8plus.sparc.stderr +++ b/tests/ui/abi/sparcv8plus.sparc.stderr @@ -1,5 +1,5 @@ error: -v8plus,-v9 - --> $DIR/sparcv8plus.rs:28:1 + --> $DIR/sparcv8plus.rs:27:1 | LL | compile_error!("-v8plus,-v9"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr b/tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr index 2c5699f2dec..a1a8383cbe7 100644 --- a/tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr +++ b/tests/ui/abi/sparcv8plus.sparc_cpu_v9.stderr @@ -1,5 +1,5 @@ error: -v8plus,+v9 - --> $DIR/sparcv8plus.rs:41:1 + --> $DIR/sparcv8plus.rs:40:1 | LL | compile_error!("-v8plus,+v9"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/sparcv8plus.sparc_cpu_v9_feature_v8plus.stderr b/tests/ui/abi/sparcv8plus.sparc_cpu_v9_feature_v8plus.stderr index 4b96e4421f9..c633ee26c51 100644 --- a/tests/ui/abi/sparcv8plus.sparc_cpu_v9_feature_v8plus.stderr +++ b/tests/ui/abi/sparcv8plus.sparc_cpu_v9_feature_v8plus.stderr @@ -1,5 +1,5 @@ error: +v8plus,+v9 - --> $DIR/sparcv8plus.rs:32:1 + --> $DIR/sparcv8plus.rs:31:1 | LL | compile_error!("+v8plus,+v9"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/sparcv8plus.sparc_feature_v8plus.stderr b/tests/ui/abi/sparcv8plus.sparc_feature_v8plus.stderr index dfdec88961b..bad8adc1599 100644 --- a/tests/ui/abi/sparcv8plus.sparc_feature_v8plus.stderr +++ b/tests/ui/abi/sparcv8plus.sparc_feature_v8plus.stderr @@ -1,5 +1,5 @@ error: +v8plus,-v9 (FIXME) - --> $DIR/sparcv8plus.rs:37:1 + --> $DIR/sparcv8plus.rs:36:1 | LL | compile_error!("+v8plus,-v9 (FIXME)"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/abi/sparcv8plus.sparcv8plus.stderr b/tests/ui/abi/sparcv8plus.sparcv8plus.stderr index 4b96e4421f9..c633ee26c51 100644 --- a/tests/ui/abi/sparcv8plus.sparcv8plus.stderr +++ b/tests/ui/abi/sparcv8plus.sparcv8plus.stderr @@ -1,5 +1,5 @@ error: +v8plus,+v9 - --> $DIR/sparcv8plus.rs:32:1 + --> $DIR/sparcv8plus.rs:31:1 | LL | compile_error!("+v8plus,+v9"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32d.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32d.stderr index 8742d4bd82c..c67c913d2a6 100644 --- a/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32d.stderr +++ b/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32d.stderr @@ -1,35 +1,35 @@ error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:27:18 + --> $DIR/bad-reg.rs:26:18 | LL | asm!("", out("$r0") _); | ^^^^^^^^^^^^ error: invalid register `$tp`: reserved for TLS - --> $DIR/bad-reg.rs:29:18 + --> $DIR/bad-reg.rs:28:18 | LL | asm!("", out("$tp") _); | ^^^^^^^^^^^^ error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:31:18 + --> $DIR/bad-reg.rs:30:18 | LL | asm!("", out("$sp") _); | ^^^^^^^^^^^^ error: invalid register `$r21`: reserved by the ABI - --> $DIR/bad-reg.rs:33:18 + --> $DIR/bad-reg.rs:32:18 | LL | asm!("", out("$r21") _); | ^^^^^^^^^^^^^ error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:35:18 + --> $DIR/bad-reg.rs:34:18 | LL | asm!("", out("$fp") _); | ^^^^^^^^^^^^ error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:37:18 + --> $DIR/bad-reg.rs:36:18 | LL | asm!("", out("$r31") _); | ^^^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32s.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32s.stderr index e6cb6e40c70..99c071919ac 100644 --- a/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32s.stderr +++ b/tests/ui/asm/loongarch/bad-reg.loongarch32_ilp32s.stderr @@ -1,59 +1,59 @@ error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:27:18 + --> $DIR/bad-reg.rs:26:18 | LL | asm!("", out("$r0") _); | ^^^^^^^^^^^^ error: invalid register `$tp`: reserved for TLS - --> $DIR/bad-reg.rs:29:18 + --> $DIR/bad-reg.rs:28:18 | LL | asm!("", out("$tp") _); | ^^^^^^^^^^^^ error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:31:18 + --> $DIR/bad-reg.rs:30:18 | LL | asm!("", out("$sp") _); | ^^^^^^^^^^^^ error: invalid register `$r21`: reserved by the ABI - --> $DIR/bad-reg.rs:33:18 + --> $DIR/bad-reg.rs:32:18 | LL | asm!("", out("$r21") _); | ^^^^^^^^^^^^^ error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:35:18 + --> $DIR/bad-reg.rs:34:18 | LL | asm!("", out("$fp") _); | ^^^^^^^^^^^^ error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:37:18 + --> $DIR/bad-reg.rs:36:18 | LL | asm!("", out("$r31") _); | ^^^^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:41:26 + --> $DIR/bad-reg.rs:40:26 | LL | asm!("/* {} */", in(freg) f); | ^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:43:26 + --> $DIR/bad-reg.rs:42:26 | LL | asm!("/* {} */", out(freg) _); | ^^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:45:26 + --> $DIR/bad-reg.rs:44:26 | LL | asm!("/* {} */", in(freg) d); | ^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:47:26 + --> $DIR/bad-reg.rs:46:26 | LL | asm!("/* {} */", out(freg) d); | ^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr index 8742d4bd82c..c67c913d2a6 100644 --- a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr +++ b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64d.stderr @@ -1,35 +1,35 @@ error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:27:18 + --> $DIR/bad-reg.rs:26:18 | LL | asm!("", out("$r0") _); | ^^^^^^^^^^^^ error: invalid register `$tp`: reserved for TLS - --> $DIR/bad-reg.rs:29:18 + --> $DIR/bad-reg.rs:28:18 | LL | asm!("", out("$tp") _); | ^^^^^^^^^^^^ error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:31:18 + --> $DIR/bad-reg.rs:30:18 | LL | asm!("", out("$sp") _); | ^^^^^^^^^^^^ error: invalid register `$r21`: reserved by the ABI - --> $DIR/bad-reg.rs:33:18 + --> $DIR/bad-reg.rs:32:18 | LL | asm!("", out("$r21") _); | ^^^^^^^^^^^^^ error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:35:18 + --> $DIR/bad-reg.rs:34:18 | LL | asm!("", out("$fp") _); | ^^^^^^^^^^^^ error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:37:18 + --> $DIR/bad-reg.rs:36:18 | LL | asm!("", out("$r31") _); | ^^^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr index e6cb6e40c70..99c071919ac 100644 --- a/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr +++ b/tests/ui/asm/loongarch/bad-reg.loongarch64_lp64s.stderr @@ -1,59 +1,59 @@ error: invalid register `$r0`: constant zero cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:27:18 + --> $DIR/bad-reg.rs:26:18 | LL | asm!("", out("$r0") _); | ^^^^^^^^^^^^ error: invalid register `$tp`: reserved for TLS - --> $DIR/bad-reg.rs:29:18 + --> $DIR/bad-reg.rs:28:18 | LL | asm!("", out("$tp") _); | ^^^^^^^^^^^^ error: invalid register `$sp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:31:18 + --> $DIR/bad-reg.rs:30:18 | LL | asm!("", out("$sp") _); | ^^^^^^^^^^^^ error: invalid register `$r21`: reserved by the ABI - --> $DIR/bad-reg.rs:33:18 + --> $DIR/bad-reg.rs:32:18 | LL | asm!("", out("$r21") _); | ^^^^^^^^^^^^^ error: invalid register `$fp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:35:18 + --> $DIR/bad-reg.rs:34:18 | LL | asm!("", out("$fp") _); | ^^^^^^^^^^^^ error: invalid register `$r31`: $r31 is used internally by LLVM and cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:37:18 + --> $DIR/bad-reg.rs:36:18 | LL | asm!("", out("$r31") _); | ^^^^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:41:26 + --> $DIR/bad-reg.rs:40:26 | LL | asm!("/* {} */", in(freg) f); | ^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:43:26 + --> $DIR/bad-reg.rs:42:26 | LL | asm!("/* {} */", out(freg) _); | ^^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:45:26 + --> $DIR/bad-reg.rs:44:26 | LL | asm!("/* {} */", in(freg) d); | ^^^^^^^^^^ error: register class `freg` requires at least one of the following target features: d, f - --> $DIR/bad-reg.rs:47:26 + --> $DIR/bad-reg.rs:46:26 | LL | asm!("/* {} */", out(freg) d); | ^^^^^^^^^^^ diff --git a/tests/ui/asm/loongarch/bad-reg.rs b/tests/ui/asm/loongarch/bad-reg.rs index 0d3eba07f14..cca37dd2e8e 100644 --- a/tests/ui/asm/loongarch/bad-reg.rs +++ b/tests/ui/asm/loongarch/bad-reg.rs @@ -1,7 +1,6 @@ //@ add-core-stubs //@ needs-asm-support //@ revisions: loongarch32_ilp32d loongarch32_ilp32s loongarch64_lp64d loongarch64_lp64s -//@ min-llvm-version: 20 //@[loongarch32_ilp32d] compile-flags: --target loongarch32-unknown-none //@[loongarch32_ilp32d] needs-llvm-components: loongarch //@[loongarch32_ilp32s] compile-flags: --target loongarch32-unknown-none-softfloat diff --git a/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed b/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed index bce6148f9e1..ae4d0107aee 100644 --- a/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed +++ b/tests/ui/associated-types/associated-types-for-unimpl-trait.fixed @@ -8,7 +8,7 @@ trait Get { } trait Other { - fn uhoh<U: Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Sized, Self: Get, Self: Get {} + fn uhoh<U: Get>(&self, foo: U, bar: <Self as Get>::Value) where Self: Sized, Self: Get {} //~^ ERROR the trait bound `Self: Get` is not satisfied //~| ERROR the trait bound `Self: Get` is not satisfied } diff --git a/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr b/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr new file mode 100644 index 00000000000..506fc6e0965 --- /dev/null +++ b/tests/ui/borrowck/format-args-temporary-scopes.e2024.stderr @@ -0,0 +1,27 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/format-args-temporary-scopes.rs:13:25 + | +LL | println!("{:?}", { &temp() }); + | ---^^^^^--- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error[E0716]: temporary value dropped while borrowed + --> $DIR/format-args-temporary-scopes.rs:19:29 + | +LL | println!("{:?}{:?}", { &temp() }, ()); + | ---^^^^^--- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary value which is freed while still in use + | borrow later used here + | + = note: consider using a `let` binding to create a longer lived value + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/tests/ui/borrowck/format-args-temporary-scopes.rs b/tests/ui/borrowck/format-args-temporary-scopes.rs new file mode 100644 index 00000000000..2641058accb --- /dev/null +++ b/tests/ui/borrowck/format-args-temporary-scopes.rs @@ -0,0 +1,21 @@ +//! Test for #145784 as it relates to format arguments: arguments to macros such as `println!` +//! should obey normal temporary scoping rules. +//@ revisions: e2021 e2024 +//@ [e2021] check-pass +//@ [e2021] edition: 2021 +//@ [e2024] edition: 2024 + +fn temp() {} + +fn main() { + // In Rust 2024, block tail expressions are temporary scopes, so the result of `temp()` is + // dropped after evaluating `&temp()`. + println!("{:?}", { &temp() }); + //[e2024]~^ ERROR: temporary value dropped while borrowed [E0716] + + // In Rust 1.89, `format_args!` extended the lifetime of all extending expressions in its + // arguments when provided with two or more arguments. This caused the result of `temp()` to + // outlive the result of the block, making this compile. + println!("{:?}{:?}", { &temp() }, ()); + //[e2024]~^ ERROR: temporary value dropped while borrowed [E0716] +} diff --git a/tests/ui/c-variadic/no-closure.rs b/tests/ui/c-variadic/no-closure.rs index c0b77786e8b..830ed962a8c 100644 --- a/tests/ui/c-variadic/no-closure.rs +++ b/tests/ui/c-variadic/no-closure.rs @@ -4,14 +4,17 @@ // Check that `...` in closures is rejected. const F: extern "C" fn(...) = |_: ...| {}; -//~^ ERROR C-variadic type `...` may not be nested inside another type +//~^ ERROR: unexpected `...` +//~| NOTE: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list fn foo() { let f = |...| {}; - //~^ ERROR: `..` patterns are not allowed here - //~| ERROR: unexpected `...` + //~^ ERROR: unexpected `...` + //~| NOTE: not a valid pattern + //~| NOTE: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list let f = |_: ...| {}; - //~^ ERROR C-variadic type `...` may not be nested inside another type + //~^ ERROR: unexpected `...` + //~| NOTE: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list f(1i64) } diff --git a/tests/ui/c-variadic/no-closure.stderr b/tests/ui/c-variadic/no-closure.stderr index 77bd106bb95..0946c4632e6 100644 --- a/tests/ui/c-variadic/no-closure.stderr +++ b/tests/ui/c-variadic/no-closure.stderr @@ -1,35 +1,26 @@ -error[E0743]: C-variadic type `...` may not be nested inside another type +error: unexpected `...` --> $DIR/no-closure.rs:6:35 | LL | const F: extern "C" fn(...) = |_: ...| {}; | ^^^ + | + = note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list error: unexpected `...` - --> $DIR/no-closure.rs:10:14 + --> $DIR/no-closure.rs:11:14 | LL | let f = |...| {}; | ^^^ not a valid pattern | -help: for a rest pattern, use `..` instead of `...` - | -LL - let f = |...| {}; -LL + let f = |..| {}; - | + = note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list -error[E0743]: C-variadic type `...` may not be nested inside another type - --> $DIR/no-closure.rs:14:17 +error: unexpected `...` + --> $DIR/no-closure.rs:16:17 | LL | let f = |_: ...| {}; | ^^^ - -error: `..` patterns are not allowed here - --> $DIR/no-closure.rs:10:14 - | -LL | let f = |...| {}; - | ^^^ | - = note: only allowed in tuple, tuple struct, and slice patterns + = note: only `extern "C"` and `extern "C-unwind"` functions may have a C variable argument list -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0743`. diff --git a/tests/ui/coercion/coerce-block-tail.stderr b/tests/ui/coercion/coerce-block-tail.stderr index 1301f3b7813..b358401b706 100644 --- a/tests/ui/coercion/coerce-block-tail.stderr +++ b/tests/ui/coercion/coerce-block-tail.stderr @@ -6,10 +6,11 @@ LL | let _: &i32 = & { Box::new(1i32) }; | = note: expected type `i32` found struct `Box<i32>` -help: consider unboxing the value +help: consider removing the Box + | +LL - let _: &i32 = & { Box::new(1i32) }; +LL + let _: &i32 = & { 1i32 }; | -LL | let _: &i32 = & { *Box::new(1i32) }; - | + error: aborting due to 1 previous error diff --git a/tests/ui/coercion/coerce-box-new-to-unboxed.rs b/tests/ui/coercion/coerce-box-new-to-unboxed.rs new file mode 100644 index 00000000000..63ff0fc4e23 --- /dev/null +++ b/tests/ui/coercion/coerce-box-new-to-unboxed.rs @@ -0,0 +1,4 @@ +fn main() { + let _: String = Box::new(String::new()); + //~^ ERROR mismatched types +} diff --git a/tests/ui/coercion/coerce-box-new-to-unboxed.stderr b/tests/ui/coercion/coerce-box-new-to-unboxed.stderr new file mode 100644 index 00000000000..bdd962686e4 --- /dev/null +++ b/tests/ui/coercion/coerce-box-new-to-unboxed.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/coerce-box-new-to-unboxed.rs:2:21 + | +LL | let _: String = Box::new(String::new()); + | ------ ^^^^^^^^^^^^^^^^^^^^^^^ expected `String`, found `Box<String>` + | | + | expected due to this + | + = note: expected struct `String` + found struct `Box<String>` +help: consider removing the Box + | +LL - let _: String = Box::new(String::new()); +LL + let _: String = String::new(); + | + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs b/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs index e2ba459f8dd..1bfd7c34656 100644 --- a/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs +++ b/tests/ui/const-generics/adt_const_params/auxiliary/unsized_const_param.rs @@ -1,6 +1,6 @@ #![feature(adt_const_params, unsized_const_params)] -#[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)] +#[derive(std::marker::ConstParamTy, Eq, PartialEq)] pub struct Foo([u8]); #[derive(std::marker::ConstParamTy, Eq, PartialEq)] diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs index 35539193a27..d482e7fad06 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.rs @@ -1,7 +1,7 @@ #![allow(incomplete_features)] #![feature(adt_const_params, unsized_const_params)] -fn check(_: impl std::marker::UnsizedConstParamTy) {} +fn check(_: impl std::marker::ConstParamTy_) {} fn main() { check(main); //~ error: `fn() {main}` can't be used as a const parameter type diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr index c05584ef909..ff514f5608f 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr @@ -2,15 +2,15 @@ error[E0277]: `fn() {main}` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:7:11 | LL | check(main); - | ----- ^^^^ the trait `UnsizedConstParamTy` is not implemented for fn item `fn() {main}` + | ----- ^^^^ the trait `ConstParamTy_` is not implemented for fn item `fn() {main}` | | | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::ConstParamTy_) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: use parentheses to call this function | LL | check(main()); @@ -24,12 +24,12 @@ LL | check(|| {}); | | | required by a bound introduced by this call | - = help: the trait `UnsizedConstParamTy` is not implemented for closure `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` + = help: the trait `ConstParamTy_` is not implemented for closure `{closure@$DIR/const_param_ty_bad.rs:8:11: 8:13}` note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::ConstParamTy_) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: use parentheses to call this closure | LL - check(|| {}); @@ -40,15 +40,15 @@ error[E0277]: `fn()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:9:11 | LL | check(main as fn()); - | ----- ^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `fn()` + | ----- ^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `fn()` | | | required by a bound introduced by this call | note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::ConstParamTy_) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: use parentheses to call this function pointer | LL | check(main as fn()()); @@ -58,16 +58,16 @@ error[E0277]: `&mut ()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:10:11 | LL | check(&mut ()); - | ----- ^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `&mut ()` + | ----- ^^^^^^^ the trait `ConstParamTy_` is not implemented for `&mut ()` | | | required by a bound introduced by this call | - = note: `UnsizedConstParamTy` is implemented for `&()`, but not for `&mut ()` + = note: `ConstParamTy_` is implemented for `&()`, but not for `&mut ()` note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::ConstParamTy_) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` help: consider removing the leading `&`-reference | LL - check(&mut ()); @@ -78,31 +78,31 @@ error[E0277]: `*mut ()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:11:11 | LL | check(&mut () as *mut ()); - | ----- ^^^^^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `*mut ()` + | ----- ^^^^^^^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `*mut ()` | | | required by a bound introduced by this call | - = help: the trait `UnsizedConstParamTy` is implemented for `()` + = help: the trait `ConstParamTy_` is implemented for `()` note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::ConstParamTy_) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: `*const ()` can't be used as a const parameter type --> $DIR/const_param_ty_bad.rs:12:11 | LL | check(&() as *const ()); - | ----- ^^^^^^^^^^^^^^^^ the trait `UnsizedConstParamTy` is not implemented for `*const ()` + | ----- ^^^^^^^^^^^^^^^^ the trait `ConstParamTy_` is not implemented for `*const ()` | | | required by a bound introduced by this call | - = help: the trait `UnsizedConstParamTy` is implemented for `()` + = help: the trait `ConstParamTy_` is implemented for `()` note: required by a bound in `check` --> $DIR/const_param_ty_bad.rs:4:18 | -LL | fn check(_: impl std::marker::UnsizedConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check(_: impl std::marker::ConstParamTy_) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error: aborting due to 6 previous errors diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.rs index 6a553c2e085..2fcf872c99a 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.rs @@ -1,12 +1,9 @@ #![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] -use std::marker::{ConstParamTy_, UnsizedConstParamTy}; +use std::marker::ConstParamTy_; fn foo(a: &dyn ConstParamTy_) {} //~^ ERROR: the trait `ConstParamTy_` -fn bar(a: &dyn UnsizedConstParamTy) {} -//~^ ERROR: the trait `UnsizedConstParamTy` - fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr index c71ec24dda3..ce695ff66d5 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_dyn_compatibility.stderr @@ -15,23 +15,6 @@ LL - fn foo(a: &dyn ConstParamTy_) {} LL + fn foo(a: &impl ConstParamTy_) {} | -error[E0038]: the trait `UnsizedConstParamTy` is not dyn compatible - --> $DIR/const_param_ty_dyn_compatibility.rs:9:16 - | -LL | fn bar(a: &dyn UnsizedConstParamTy) {} - | ^^^^^^^^^^^^^^^^^^^ `UnsizedConstParamTy` is not dyn compatible - | -note: for a trait to be dyn compatible it needs to allow building a vtable - for more information, visit <https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility> - --> $SRC_DIR/core/src/cmp.rs:LL:COL - | - = note: the trait is not dyn compatible because it uses `Self` as a type parameter -help: consider using an opaque type instead - | -LL - fn bar(a: &dyn UnsizedConstParamTy) {} -LL + fn bar(a: &impl UnsizedConstParamTy) {} - | - -error: aborting due to 2 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0038`. diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs index 7ffdafa33e9..a86d74275de 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.rs @@ -4,7 +4,7 @@ #[derive(PartialEq, Eq)] struct NotParam; -fn check<T: std::marker::UnsizedConstParamTy + ?Sized>() {} +fn check<T: std::marker::ConstParamTy_ + ?Sized>() {} fn main() { check::<&NotParam>(); //~ error: `NotParam` can't be used as a const parameter type diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr index 158e76630f3..ca2aa3adcb7 100644 --- a/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr +++ b/tests/ui/const-generics/adt_const_params/const_param_ty_generic_bounds_do_not_hold.stderr @@ -4,17 +4,17 @@ error[E0277]: `NotParam` can't be used as a const parameter type LL | check::<&NotParam>(); | ^^^^^^^^^ unsatisfied trait bound | -help: the trait `UnsizedConstParamTy` is not implemented for `NotParam` +help: the trait `ConstParamTy_` is not implemented for `NotParam` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:5:1 | LL | struct NotParam; | ^^^^^^^^^^^^^^^ - = note: required for `&NotParam` to implement `UnsizedConstParamTy` + = note: required for `&NotParam` to implement `ConstParamTy_` note: required by a bound in `check` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 | -LL | fn check<T: std::marker::UnsizedConstParamTy + ?Sized>() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check<T: std::marker::ConstParamTy_ + ?Sized>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:11:13 @@ -22,17 +22,17 @@ error[E0277]: `NotParam` can't be used as a const parameter type LL | check::<[NotParam]>(); | ^^^^^^^^^^ unsatisfied trait bound | -help: the trait `UnsizedConstParamTy` is not implemented for `NotParam` +help: the trait `ConstParamTy_` is not implemented for `NotParam` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:5:1 | LL | struct NotParam; | ^^^^^^^^^^^^^^^ - = note: required for `[NotParam]` to implement `UnsizedConstParamTy` + = note: required for `[NotParam]` to implement `ConstParamTy_` note: required by a bound in `check` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 | -LL | fn check<T: std::marker::UnsizedConstParamTy + ?Sized>() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check<T: std::marker::ConstParamTy_ + ?Sized>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error[E0277]: `NotParam` can't be used as a const parameter type --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:12:13 @@ -40,17 +40,17 @@ error[E0277]: `NotParam` can't be used as a const parameter type LL | check::<[NotParam; 17]>(); | ^^^^^^^^^^^^^^ unsatisfied trait bound | -help: the trait `UnsizedConstParamTy` is not implemented for `NotParam` +help: the trait `ConstParamTy_` is not implemented for `NotParam` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:5:1 | LL | struct NotParam; | ^^^^^^^^^^^^^^^ - = note: required for `[NotParam; 17]` to implement `UnsizedConstParamTy` + = note: required for `[NotParam; 17]` to implement `ConstParamTy_` note: required by a bound in `check` --> $DIR/const_param_ty_generic_bounds_do_not_hold.rs:7:13 | -LL | fn check<T: std::marker::UnsizedConstParamTy + ?Sized>() {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` +LL | fn check<T: std::marker::ConstParamTy_ + ?Sized>() {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check` error: aborting due to 3 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 98a8eb6ee95..24bbc5a9a23 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 @@ -3,7 +3,7 @@ #![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] -use std::marker::UnsizedConstParamTy; +use std::marker::{ConstParamTy, ConstParamTy_}; #[derive(PartialEq, Eq)] struct S<T> { @@ -11,15 +11,15 @@ struct S<T> { gen: T, } -impl<T: UnsizedConstParamTy> UnsizedConstParamTy for S<T> {} +impl<T: ConstParamTy_> ConstParamTy_ for S<T> {} -#[derive(PartialEq, Eq, UnsizedConstParamTy)] +#[derive(PartialEq, Eq, ConstParamTy)] struct D<T> { field: u8, gen: T, } -fn check<T: UnsizedConstParamTy + ?Sized>() {} +fn check<T: ConstParamTy_ + ?Sized>() {} fn main() { check::<u8>(); 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 8b3d0546010..0614ea97b1a 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 @@ -7,10 +7,10 @@ struct NotParam; #[derive(PartialEq, Eq)] struct CantParam(NotParam); -impl std::marker::UnsizedConstParamTy for CantParam {} +impl std::marker::ConstParamTy_ for CantParam {} //~^ error: the trait `ConstParamTy_` cannot be implemented for this type -#[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)] +#[derive(std::marker::ConstParamTy, Eq, PartialEq)] //~^ error: the trait `ConstParamTy_` cannot be implemented for this type struct CantParamDerive(NotParam); 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 a4e5736d834..fd1836802c4 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 @@ -1,17 +1,17 @@ error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type - --> $DIR/const_param_ty_impl_bad_field.rs:10:43 + --> $DIR/const_param_ty_impl_bad_field.rs:10:37 | LL | struct CantParam(NotParam); | -------- this field does not implement `ConstParamTy_` LL | -LL | impl std::marker::UnsizedConstParamTy for CantParam {} - | ^^^^^^^^^ +LL | impl std::marker::ConstParamTy_ for CantParam {} + | ^^^^^^^^^ 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::UnsizedConstParamTy, Eq, PartialEq)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[derive(std::marker::ConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ LL | LL | struct CantParamDerive(NotParam); | -------- this field does not implement `ConstParamTy_` 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 e743b78fd13..a1c8eccfb09 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 @@ -3,20 +3,20 @@ #[derive(PartialEq, Eq)] struct ImplementsConstParamTy; -impl std::marker::UnsizedConstParamTy for ImplementsConstParamTy {} +impl std::marker::ConstParamTy_ for ImplementsConstParamTy {} struct CantParam(ImplementsConstParamTy); -impl std::marker::UnsizedConstParamTy for CantParam {} +impl std::marker::ConstParamTy_ for CantParam {} //~^ error: the type `CantParam` does not `#[derive(PartialEq)]` //~| ERROR the trait bound `CantParam: Eq` is not satisfied -#[derive(std::marker::UnsizedConstParamTy)] +#[derive(std::marker::ConstParamTy)] //~^ error: the type `CantParamDerive` does not `#[derive(PartialEq)]` //~| ERROR the trait bound `CantParamDerive: Eq` is not satisfied struct CantParamDerive(ImplementsConstParamTy); -fn check<T: std::marker::UnsizedConstParamTy>() {} +fn check<T: std::marker::ConstParamTy_>() {} fn main() { check::<ImplementsConstParamTy>(); 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 d3141381db8..c6b791ed967 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 @@ -1,10 +1,10 @@ error[E0277]: the trait bound `CantParam: Eq` is not satisfied - --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:43 + --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:37 | -LL | impl std::marker::UnsizedConstParamTy for CantParam {} - | ^^^^^^^^^ the trait `Eq` is not implemented for `CantParam` +LL | impl std::marker::ConstParamTy_ for CantParam {} + | ^^^^^^^^^ the trait `Eq` is not implemented for `CantParam` | -note: required by a bound in `UnsizedConstParamTy` +note: required by a bound in `ConstParamTy_` --> $SRC_DIR/core/src/marker.rs:LL:COL help: consider annotating `CantParam` with `#[derive(Eq)]` | @@ -13,26 +13,26 @@ LL | struct CantParam(ImplementsConstParamTy); | error[E0277]: the type `CantParam` does not `#[derive(PartialEq)]` - --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:43 + --> $DIR/const_param_ty_impl_no_structural_eq.rs:10:37 | -LL | impl std::marker::UnsizedConstParamTy for CantParam {} - | ^^^^^^^^^ unsatisfied trait bound +LL | impl std::marker::ConstParamTy_ for CantParam {} + | ^^^^^^^^^ unsatisfied trait bound | help: the trait `StructuralPartialEq` is not implemented for `CantParam` --> $DIR/const_param_ty_impl_no_structural_eq.rs:8:1 | LL | struct CantParam(ImplementsConstParamTy); | ^^^^^^^^^^^^^^^^ -note: required by a bound in `UnsizedConstParamTy` +note: required by a bound in `ConstParamTy_` --> $SRC_DIR/core/src/marker.rs:LL:COL error[E0277]: the trait bound `CantParamDerive: Eq` is not satisfied --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10 | -LL | #[derive(std::marker::UnsizedConstParamTy)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `CantParamDerive` +LL | #[derive(std::marker::ConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `CantParamDerive` | -note: required by a bound in `UnsizedConstParamTy` +note: required by a bound in `ConstParamTy_` --> $SRC_DIR/core/src/marker.rs:LL:COL help: consider annotating `CantParamDerive` with `#[derive(Eq)]` | @@ -43,15 +43,15 @@ LL | struct CantParamDerive(ImplementsConstParamTy); error[E0277]: the type `CantParamDerive` does not `#[derive(PartialEq)]` --> $DIR/const_param_ty_impl_no_structural_eq.rs:14:10 | -LL | #[derive(std::marker::UnsizedConstParamTy)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound +LL | #[derive(std::marker::ConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound | help: the trait `StructuralPartialEq` is not implemented for `CantParamDerive` --> $DIR/const_param_ty_impl_no_structural_eq.rs:17:1 | LL | struct CantParamDerive(ImplementsConstParamTy); | ^^^^^^^^^^^^^^^^^^^^^^ -note: required by a bound in `UnsizedConstParamTy` +note: required by a bound in `ConstParamTy_` --> $SRC_DIR/core/src/marker.rs:LL:COL error: aborting due to 4 previous errors 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 index 236b3bc162a..0c9b12805f7 100644 --- 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 @@ -12,10 +12,10 @@ impl PartialEq for Union { } impl Eq for Union {} -impl std::marker::UnsizedConstParamTy for Union {} +impl std::marker::ConstParamTy_ for Union {} //~^ ERROR the trait `ConstParamTy` may not be implemented for this type -#[derive(std::marker::UnsizedConstParamTy)] +#[derive(std::marker::ConstParamTy)] //~^ ERROR this trait cannot be derived for unions union UnionDerive { a: u8, 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 index 837c289c924..cc2147b49ae 100644 --- 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 @@ -1,14 +1,14 @@ error: this trait cannot be derived for unions --> $DIR/const_param_ty_impl_union.rs:18:10 | -LL | #[derive(std::marker::UnsizedConstParamTy)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[derive(std::marker::ConstParamTy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: the trait `ConstParamTy` may not be implemented for this type - --> $DIR/const_param_ty_impl_union.rs:15:43 + --> $DIR/const_param_ty_impl_union.rs:15:37 | -LL | impl std::marker::UnsizedConstParamTy for Union {} - | ^^^^^ type is not a structure or enumeration +LL | impl std::marker::ConstParamTy_ for Union {} + | ^^^^^ type is not a structure or enumeration error: aborting due to 2 previous errors diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs index 34ea143d254..d42ef90e1b1 100644 --- a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs +++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.rs @@ -5,17 +5,14 @@ use std::marker::ConstParamTy; #[derive(ConstParamTy)] //~^ ERROR the trait `ConstParamTy_` cannot be implemented for this ty -//~| ERROR the trait `ConstParamTy_` cannot be implemented for this ty struct Foo([*const u8; 1]); #[derive(ConstParamTy)] //~^ ERROR the trait `ConstParamTy_` cannot be implemented for this ty -//~| ERROR the trait `ConstParamTy_` cannot be implemented for this ty struct Foo2([*mut u8; 1]); #[derive(ConstParamTy)] //~^ ERROR the trait `ConstParamTy_` cannot be implemented for this ty -//~| ERROR the trait `ConstParamTy_` cannot be implemented for this ty struct Foo3([fn(); 1]); fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr index 6b8d2394a86..442ec6b96ce 100644 --- a/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr +++ b/tests/ui/const-generics/adt_const_params/nested_bad_const_param_ty.stderr @@ -3,91 +3,46 @@ error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type | LL | #[derive(ConstParamTy)] | ^^^^^^^^^^^^ -... +LL | LL | struct Foo([*const u8; 1]); | -------------- this field does not implement `ConstParamTy_` | note: the `ConstParamTy_` impl for `[*const u8; 1]` requires that `*const u8: ConstParamTy_` - --> $DIR/nested_bad_const_param_ty.rs:9:12 + --> $DIR/nested_bad_const_param_ty.rs:8:12 | LL | struct Foo([*const u8; 1]); | ^^^^^^^^^^^^^^ error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type - --> $DIR/nested_bad_const_param_ty.rs:11:10 + --> $DIR/nested_bad_const_param_ty.rs:10:10 | LL | #[derive(ConstParamTy)] | ^^^^^^^^^^^^ -... +LL | LL | struct Foo2([*mut u8; 1]); | ------------ this field does not implement `ConstParamTy_` | note: the `ConstParamTy_` impl for `[*mut u8; 1]` requires that `*mut u8: ConstParamTy_` - --> $DIR/nested_bad_const_param_ty.rs:14:13 + --> $DIR/nested_bad_const_param_ty.rs:12:13 | LL | struct Foo2([*mut u8; 1]); | ^^^^^^^^^^^^ error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type - --> $DIR/nested_bad_const_param_ty.rs:16:10 + --> $DIR/nested_bad_const_param_ty.rs:14:10 | LL | #[derive(ConstParamTy)] | ^^^^^^^^^^^^ -... +LL | LL | struct Foo3([fn(); 1]); | --------- this field does not implement `ConstParamTy_` | note: the `ConstParamTy_` impl for `[fn(); 1]` requires that `fn(): ConstParamTy_` - --> $DIR/nested_bad_const_param_ty.rs:19:13 + --> $DIR/nested_bad_const_param_ty.rs:16:13 | LL | struct Foo3([fn(); 1]); | ^^^^^^^^^ -error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type - --> $DIR/nested_bad_const_param_ty.rs:6:10 - | -LL | #[derive(ConstParamTy)] - | ^^^^^^^^^^^^ -... -LL | struct Foo([*const u8; 1]); - | -------------- this field does not implement `ConstParamTy_` - | -note: the `ConstParamTy_` impl for `[*const u8; 1]` requires that `*const u8: UnsizedConstParamTy` - --> $DIR/nested_bad_const_param_ty.rs:9:12 - | -LL | struct Foo([*const u8; 1]); - | ^^^^^^^^^^^^^^ - -error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type - --> $DIR/nested_bad_const_param_ty.rs:11:10 - | -LL | #[derive(ConstParamTy)] - | ^^^^^^^^^^^^ -... -LL | struct Foo2([*mut u8; 1]); - | ------------ this field does not implement `ConstParamTy_` - | -note: the `ConstParamTy_` impl for `[*mut u8; 1]` requires that `*mut u8: UnsizedConstParamTy` - --> $DIR/nested_bad_const_param_ty.rs:14:13 - | -LL | struct Foo2([*mut u8; 1]); - | ^^^^^^^^^^^^ - -error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type - --> $DIR/nested_bad_const_param_ty.rs:16:10 - | -LL | #[derive(ConstParamTy)] - | ^^^^^^^^^^^^ -... -LL | struct Foo3([fn(); 1]); - | --------- this field does not implement `ConstParamTy_` - | -note: the `ConstParamTy_` impl for `[fn(); 1]` requires that `fn(): UnsizedConstParamTy` - --> $DIR/nested_bad_const_param_ty.rs:19:13 - | -LL | struct Foo3([fn(); 1]); - | ^^^^^^^^^ - -error: aborting due to 6 previous errors +error: aborting due to 3 previous errors For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr index b13f76eabad..72dfda50ea5 100644 --- a/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr +++ b/tests/ui/const-generics/adt_const_params/non_valtreeable_const_arg-2.stderr @@ -9,11 +9,13 @@ help: you might be missing a const parameter LL | impl<const bar: /* Type */> Wrapper<{ bar() }> { | +++++++++++++++++++++++ -error[E0741]: using function pointers as const generic parameters is forbidden +error: using function pointers as const generic parameters is forbidden --> $DIR/non_valtreeable_const_arg-2.rs:8:25 | LL | struct Wrapper<const F: fn()>; | ^^^^ + | + = note: the only supported types are integers, `bool`, and `char` error[E0599]: the function or associated item `call` exists for struct `Wrapper<function>`, but its trait bounds were not satisfied --> $DIR/non_valtreeable_const_arg-2.rs:17:26 @@ -35,5 +37,5 @@ note: the trait `Fn` must be implemented error: aborting due to 3 previous errors -Some errors have detailed explanations: E0425, E0599, E0741. +Some errors have detailed explanations: E0425, E0599. For more information about an error, try `rustc --explain E0425`. diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs index a1ee1c4cdd5..937acf2e6bb 100644 --- a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs +++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.rs @@ -1,11 +1,11 @@ #![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] -use std::marker::UnsizedConstParamTy; +use std::marker::ConstParamTy_; struct Foo; -impl UnsizedConstParamTy for &'static Foo {} +impl ConstParamTy_ for &'static Foo {} //~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr index 5ca8e6c7516..b977cf5d44e 100644 --- a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr +++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-1.stderr @@ -1,8 +1,8 @@ error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type - --> $DIR/reference_pointee_is_const_param-1.rs:8:30 + --> $DIR/reference_pointee_is_const_param-1.rs:8:24 | -LL | impl UnsizedConstParamTy for &'static Foo {} - | ^^^^^^^^^^^^ this field does not implement `ConstParamTy_` +LL | impl ConstParamTy_ for &'static Foo {} + | ^^^^^^^^^^^^ this field does not implement `ConstParamTy_` error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs index ac1b522f469..605fed26c9c 100644 --- a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs +++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.rs @@ -3,12 +3,12 @@ // Regression test for #119299 -use std::marker::UnsizedConstParamTy; +use std::marker::ConstParamTy_; #[derive(Eq, PartialEq)] struct ConstStrU(*const u8, usize); -impl UnsizedConstParamTy for &'static ConstStrU {} +impl ConstParamTy_ for &'static ConstStrU {} //~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type impl ConstStrU { diff --git a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr index 5e5f6cc642d..0fe92f253a0 100644 --- a/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr +++ b/tests/ui/const-generics/adt_const_params/reference_pointee_is_const_param-2.stderr @@ -1,8 +1,8 @@ error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type - --> $DIR/reference_pointee_is_const_param-2.rs:11:30 + --> $DIR/reference_pointee_is_const_param-2.rs:11:24 | -LL | impl UnsizedConstParamTy for &'static ConstStrU {} - | ^^^^^^^^^^^^^^^^^^ this field does not implement `ConstParamTy_` +LL | impl ConstParamTy_ for &'static ConstStrU {} + | ^^^^^^^^^^^^^^^^^^ this field does not implement `ConstParamTy_` error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs index b0934508399..0fe86adb291 100644 --- a/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs +++ b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.rs @@ -1,11 +1,11 @@ #![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] -use std::marker::UnsizedConstParamTy; +use std::marker::ConstParamTy_; trait Trait {} -impl UnsizedConstParamTy for dyn Trait {} +impl ConstParamTy_ for dyn Trait {} //~^ ERROR: the trait `ConstParamTy` may not be implemented for this type fn foo<const N: dyn Trait>() {} diff --git a/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr index 9933ba6e335..67c6314e297 100644 --- a/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr +++ b/tests/ui/const-generics/adt_const_params/trait_objects_as_a_const_generic.stderr @@ -1,8 +1,8 @@ error: the trait `ConstParamTy` may not be implemented for this type - --> $DIR/trait_objects_as_a_const_generic.rs:8:30 + --> $DIR/trait_objects_as_a_const_generic.rs:8:24 | -LL | impl UnsizedConstParamTy for dyn Trait {} - | ^^^^^^^^^ type is not a structure or enumeration +LL | impl ConstParamTy_ for dyn Trait {} + | ^^^^^^^^^ type is not a structure or enumeration error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-1.rs b/tests/ui/const-generics/adt_const_params/unsized_field-1.rs index f6e5bd6e355..5db031cb900 100644 --- a/tests/ui/const-generics/adt_const_params/unsized_field-1.rs +++ b/tests/ui/const-generics/adt_const_params/unsized_field-1.rs @@ -14,7 +14,10 @@ struct A([u8]); struct B(&'static [u8]); #[derive(ConstParamTy, Eq, PartialEq)] -//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type struct C(unsized_const_param::Foo); +#[derive(std::marker::ConstParamTy, Eq, PartialEq)] +//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type +struct D(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); + fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr b/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr index 3089b30bd76..a5ae5c726da 100644 --- a/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr +++ b/tests/ui/const-generics/adt_const_params/unsized_field-1.stderr @@ -6,6 +6,12 @@ LL | #[derive(ConstParamTy, Eq, PartialEq)] LL | LL | struct A([u8]); | ---- this field does not implement `ConstParamTy_` + | +note: the `ConstParamTy_` impl for `[u8]` requires that `unstable feature: `unsized_const_params`` + --> $DIR/unsized_field-1.rs:10:10 + | +LL | struct A([u8]); + | ^^^^ error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type --> $DIR/unsized_field-1.rs:12:10 @@ -15,15 +21,27 @@ LL | #[derive(ConstParamTy, Eq, PartialEq)] LL | LL | struct B(&'static [u8]); | ------------- this field does not implement `ConstParamTy_` + | +note: the `ConstParamTy_` impl for `&'static [u8]` requires that `unstable feature: `unsized_const_params`` + --> $DIR/unsized_field-1.rs:14:10 + | +LL | struct B(&'static [u8]); + | ^^^^^^^^^^^^^ error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type - --> $DIR/unsized_field-1.rs:16:10 + --> $DIR/unsized_field-1.rs:19:10 | -LL | #[derive(ConstParamTy, Eq, PartialEq)] - | ^^^^^^^^^^^^ +LL | #[derive(std::marker::ConstParamTy, Eq, PartialEq)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ LL | -LL | struct C(unsized_const_param::Foo); - | ------------------------ this field does not implement `ConstParamTy_` +LL | struct D(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); + | ---------------------------------------------------------- this field does not implement `ConstParamTy_` + | +note: the `ConstParamTy_` impl for `GenericNotUnsizedParam<&'static [u8]>` requires that `unstable feature: `unsized_const_params`` + --> $DIR/unsized_field-1.rs:21:10 + | +LL | struct D(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-2.rs b/tests/ui/const-generics/adt_const_params/unsized_field-2.rs deleted file mode 100644 index e4a3a481b4e..00000000000 --- a/tests/ui/const-generics/adt_const_params/unsized_field-2.rs +++ /dev/null @@ -1,14 +0,0 @@ -//@ aux-build:unsized_const_param.rs -#![feature(adt_const_params, unsized_const_params)] -//~^ WARN: the feature `unsized_const_params` is incomplete - -extern crate unsized_const_param; - -#[derive(std::marker::ConstParamTy, Eq, PartialEq)] -//~^ ERROR: the trait `ConstParamTy_` cannot be implemented for this type -struct A(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); - -#[derive(std::marker::UnsizedConstParamTy, Eq, PartialEq)] -struct B(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); - -fn main() {} diff --git a/tests/ui/const-generics/adt_const_params/unsized_field-2.stderr b/tests/ui/const-generics/adt_const_params/unsized_field-2.stderr deleted file mode 100644 index cef70ca0463..00000000000 --- a/tests/ui/const-generics/adt_const_params/unsized_field-2.stderr +++ /dev/null @@ -1,27 +0,0 @@ -warning: the feature `unsized_const_params` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/unsized_field-2.rs:2:30 - | -LL | #![feature(adt_const_params, unsized_const_params)] - | ^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #95174 <https://github.com/rust-lang/rust/issues/95174> for more information - = note: `#[warn(incomplete_features)]` on by default - -error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type - --> $DIR/unsized_field-2.rs:7:10 - | -LL | #[derive(std::marker::ConstParamTy, Eq, PartialEq)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | struct A(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); - | ---------------------------------------------------------- this field does not implement `ConstParamTy_` - | -note: the `ConstParamTy_` impl for `GenericNotUnsizedParam<&'static [u8]>` requires that `&'static [u8]: ConstParamTy_` - --> $DIR/unsized_field-2.rs:9:10 - | -LL | struct A(unsized_const_param::GenericNotUnsizedParam<&'static [u8]>); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 1 previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.rs b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.rs index 311f507d3c7..500e8e22b0e 100644 --- a/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.rs +++ b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.rs @@ -7,7 +7,6 @@ use std::marker::ConstParamTy; #[derive(Debug, PartialEq, Eq, ConstParamTy)] //~^ ERROR the trait `ConstParamTy_` -//~| ERROR the trait `ConstParamTy_` struct Foo { nested: &'static Bar<dyn std::fmt::Debug>, //~^ ERROR the size for values diff --git a/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr index 992a27c1c0e..d4aeb91999c 100644 --- a/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr +++ b/tests/ui/const-generics/adt_const_params/unsizing-wfcheck-issue-126272.stderr @@ -1,17 +1,17 @@ error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time - --> $DIR/unsizing-wfcheck-issue-126272.rs:12:13 + --> $DIR/unsizing-wfcheck-issue-126272.rs:11:13 | LL | nested: &'static Bar<dyn std::fmt::Debug>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)` note: required by an implicit `Sized` bound in `Bar` - --> $DIR/unsizing-wfcheck-issue-126272.rs:21:12 + --> $DIR/unsizing-wfcheck-issue-126272.rs:20:12 | LL | struct Bar<T>(T); | ^ required by the implicit `Sized` requirement on this type parameter in `Bar` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>` - --> $DIR/unsizing-wfcheck-issue-126272.rs:21:12 + --> $DIR/unsizing-wfcheck-issue-126272.rs:20:12 | LL | struct Bar<T>(T); | ^ - ...if indirection were used here: `Box<T>` @@ -26,34 +26,25 @@ LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)] ... LL | nested: &'static Bar<dyn std::fmt::Debug>, | ----------------------------------------- this field does not implement `ConstParamTy_` - -error[E0204]: the trait `ConstParamTy_` cannot be implemented for this type - --> $DIR/unsizing-wfcheck-issue-126272.rs:8:32 | -LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)] - | ^^^^^^^^^^^^ -... -LL | nested: &'static Bar<dyn std::fmt::Debug>, - | ----------------------------------------- this field does not implement `ConstParamTy_` - | -note: the `ConstParamTy_` impl for `&'static Bar<(dyn Debug + 'static)>` requires that `(dyn Debug + 'static): Eq` - --> $DIR/unsizing-wfcheck-issue-126272.rs:12:13 +note: the `ConstParamTy_` impl for `&'static Bar<(dyn Debug + 'static)>` requires that `(dyn Debug + 'static): ConstParamTy_` + --> $DIR/unsizing-wfcheck-issue-126272.rs:11:13 | LL | nested: &'static Bar<dyn std::fmt::Debug>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: the `ConstParamTy_` impl for `&'static Bar<(dyn Debug + 'static)>` requires that `(dyn Debug + 'static): Sized` - --> $DIR/unsizing-wfcheck-issue-126272.rs:12:13 +note: the `ConstParamTy_` impl for `&'static Bar<(dyn Debug + 'static)>` requires that `(dyn Debug + 'static): Eq` + --> $DIR/unsizing-wfcheck-issue-126272.rs:11:13 | LL | nested: &'static Bar<dyn std::fmt::Debug>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: the `ConstParamTy_` impl for `&'static Bar<(dyn Debug + 'static)>` requires that `(dyn Debug + 'static): UnsizedConstParamTy` - --> $DIR/unsizing-wfcheck-issue-126272.rs:12:13 +note: the `ConstParamTy_` impl for `&'static Bar<(dyn Debug + 'static)>` requires that `(dyn Debug + 'static): Sized` + --> $DIR/unsizing-wfcheck-issue-126272.rs:11:13 | LL | nested: &'static Bar<dyn std::fmt::Debug>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time - --> $DIR/unsizing-wfcheck-issue-126272.rs:12:5 + --> $DIR/unsizing-wfcheck-issue-126272.rs:11:5 | LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)] | ----- in this derive macro expansion @@ -64,7 +55,7 @@ LL | nested: &'static Bar<dyn std::fmt::Debug>, = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)` = help: the trait `Debug` is implemented for `Bar<T>` note: required for `Bar<(dyn Debug + 'static)>` to implement `Debug` - --> $DIR/unsizing-wfcheck-issue-126272.rs:20:10 + --> $DIR/unsizing-wfcheck-issue-126272.rs:19:10 | LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)] | ^^^^^ @@ -75,7 +66,7 @@ LL | struct Bar<T>(T); = note: required for the cast from `&&&'static Bar<(dyn Debug + 'static)>` to `&dyn Debug` error[E0369]: binary operation `==` cannot be applied to type `&Bar<dyn Debug>` - --> $DIR/unsizing-wfcheck-issue-126272.rs:12:5 + --> $DIR/unsizing-wfcheck-issue-126272.rs:11:5 | LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)] | --------- in this derive macro expansion @@ -84,7 +75,7 @@ LL | nested: &'static Bar<dyn std::fmt::Debug>, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0277]: the trait bound `dyn Debug: Eq` is not satisfied - --> $DIR/unsizing-wfcheck-issue-126272.rs:12:5 + --> $DIR/unsizing-wfcheck-issue-126272.rs:11:5 | LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)] | -- in this derive macro expansion @@ -94,7 +85,7 @@ LL | nested: &'static Bar<dyn std::fmt::Debug>, | = help: the trait `Eq` is implemented for `Bar<T>` note: required for `Bar<dyn Debug>` to implement `Eq` - --> $DIR/unsizing-wfcheck-issue-126272.rs:20:28 + --> $DIR/unsizing-wfcheck-issue-126272.rs:19:28 | LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)] | ^^ unsatisfied trait bound introduced in this `derive` macro @@ -104,7 +95,7 @@ note: required by a bound in `AssertParamIsEq` --> $SRC_DIR/core/src/cmp.rs:LL:COL error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time - --> $DIR/unsizing-wfcheck-issue-126272.rs:12:5 + --> $DIR/unsizing-wfcheck-issue-126272.rs:11:5 | LL | #[derive(Debug, PartialEq, Eq, ConstParamTy)] | -- in this derive macro expansion @@ -114,12 +105,12 @@ LL | nested: &'static Bar<dyn std::fmt::Debug>, | = help: the trait `Sized` is not implemented for `dyn Debug` note: required by an implicit `Sized` bound in `Bar` - --> $DIR/unsizing-wfcheck-issue-126272.rs:21:12 + --> $DIR/unsizing-wfcheck-issue-126272.rs:20:12 | LL | struct Bar<T>(T); | ^ required by the implicit `Sized` requirement on this type parameter in `Bar` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>` - --> $DIR/unsizing-wfcheck-issue-126272.rs:21:12 + --> $DIR/unsizing-wfcheck-issue-126272.rs:20:12 | LL | struct Bar<T>(T); | ^ - ...if indirection were used here: `Box<T>` @@ -127,26 +118,26 @@ LL | struct Bar<T>(T); | this could be changed to `T: ?Sized`... error[E0277]: the size for values of type `(dyn Debug + 'static)` cannot be known at compilation time - --> $DIR/unsizing-wfcheck-issue-126272.rs:26:33 + --> $DIR/unsizing-wfcheck-issue-126272.rs:25:33 | LL | let x: Test<{ Foo { nested: &Bar(4) } }> = Test; | ^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Debug + 'static)` note: required by an implicit `Sized` bound in `Bar` - --> $DIR/unsizing-wfcheck-issue-126272.rs:21:12 + --> $DIR/unsizing-wfcheck-issue-126272.rs:20:12 | LL | struct Bar<T>(T); | ^ required by the implicit `Sized` requirement on this type parameter in `Bar` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box<T>` - --> $DIR/unsizing-wfcheck-issue-126272.rs:21:12 + --> $DIR/unsizing-wfcheck-issue-126272.rs:20:12 | LL | struct Bar<T>(T); | ^ - ...if indirection were used here: `Box<T>` | | | this could be changed to `T: ?Sized`... -error: aborting due to 8 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0204, E0277, E0369. For more information about an error, try `rustc --explain E0204`. diff --git a/tests/ui/const-generics/const-param-with-additional-obligations.rs b/tests/ui/const-generics/const-param-with-additional-obligations.rs index 98097e86c7d..5110f95d5bf 100644 --- a/tests/ui/const-generics/const-param-with-additional-obligations.rs +++ b/tests/ui/const-generics/const-param-with-additional-obligations.rs @@ -1,14 +1,14 @@ #![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] -use std::marker::UnsizedConstParamTy; +use std::marker::ConstParamTy_; #[derive(Eq, PartialEq)] struct Foo<T>(T); trait Other {} -impl<T> UnsizedConstParamTy for Foo<T> where T: Other + UnsizedConstParamTy {} +impl<T> ConstParamTy_ for Foo<T> where T: Other + ConstParamTy_ {} fn foo<const N: Foo<u8>>() {} //~^ ERROR `Foo<u8>` must implement `ConstParamTy` to be used as the type of a const generic parameter diff --git a/tests/ui/const-generics/generic_const_parameter_types/no_const_param_ty_bound.stderr b/tests/ui/const-generics/generic_const_parameter_types/no_const_param_ty_bound.stderr index 4ea323f4a5c..1eacc28b262 100644 --- a/tests/ui/const-generics/generic_const_parameter_types/no_const_param_ty_bound.stderr +++ b/tests/ui/const-generics/generic_const_parameter_types/no_const_param_ty_bound.stderr @@ -4,7 +4,7 @@ error[E0741]: `[T; N]` can't be used as a const parameter type LL | struct UsesType<T, const N: usize, const M: [T; N]>(PhantomData<T>); | ^^^^^^ | - = note: `T` must implement `UnsizedConstParamTy`, but it does not + = note: `T` must implement `ConstParamTy_`, but it does not error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/issue-66451.rs b/tests/ui/const-generics/issue-66451.rs index 0b8693e0e67..9ce7658586a 100644 --- a/tests/ui/const-generics/issue-66451.rs +++ b/tests/ui/const-generics/issue-66451.rs @@ -1,15 +1,15 @@ #![feature(adt_const_params, unsized_const_params)] #![allow(incomplete_features)] -use std::marker::UnsizedConstParamTy; +use std::marker::ConstParamTy; -#[derive(Debug, PartialEq, Eq, UnsizedConstParamTy)] +#[derive(Debug, PartialEq, Eq, ConstParamTy)] struct Foo { value: i32, nested: &'static Bar<i32>, } -#[derive(Debug, PartialEq, Eq, UnsizedConstParamTy)] +#[derive(Debug, PartialEq, Eq, ConstParamTy)] struct Bar<T>(T); struct Test<const F: Foo>; diff --git a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr index 8ea96428deb..1301ca92f01 100644 --- a/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr +++ b/tests/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr @@ -4,7 +4,7 @@ error[E0741]: `&'static (dyn A + 'static)` can't be used as a const parameter ty LL | fn test<const T: &'static dyn A>() { | ^^^^^^^^^^^^^^ | - = note: `(dyn A + 'static)` must implement `UnsizedConstParamTy`, but it does not + = note: `(dyn A + 'static)` must implement `ConstParamTy_`, but it does not error: aborting due to 1 previous error diff --git a/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr b/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr index bcb2bd255da..d970b12df6a 100644 --- a/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr +++ b/tests/ui/const-generics/slice-const-param-mismatch.adt_const_params.stderr @@ -1,14 +1,22 @@ -error[E0741]: `&'static str` can't be used as a const parameter type - --> $DIR/slice-const-param-mismatch.rs:8:29 +error[E0658]: use of unstable library feature `unsized_const_params` + --> $DIR/slice-const-param-mismatch.rs:8:20 | LL | struct ConstString<const T: &'static str>; - | ^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unsized_const_params)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required for `&'static str` to implement `ConstParamTy_` -error[E0741]: `&'static [u8]` can't be used as a const parameter type - --> $DIR/slice-const-param-mismatch.rs:11:28 +error[E0658]: use of unstable library feature `unsized_const_params` + --> $DIR/slice-const-param-mismatch.rs:11:19 | LL | struct ConstBytes<const T: &'static [u8]>; - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unsized_const_params)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required for `&'static [u8]` to implement `ConstParamTy_` error[E0308]: mismatched types --> $DIR/slice-const-param-mismatch.rs:17:35 @@ -45,5 +53,5 @@ LL | let _: ConstBytes<b"AAA"> = ConstBytes::<b"BBB">; error: aborting due to 5 previous errors -Some errors have detailed explanations: E0308, E0741. +Some errors have detailed explanations: E0308, E0658. For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/const-generics/slice-const-param.rs b/tests/ui/const-generics/slice-const-param.rs index 1c5088b5283..8b5e934149e 100644 --- a/tests/ui/const-generics/slice-const-param.rs +++ b/tests/ui/const-generics/slice-const-param.rs @@ -12,7 +12,7 @@ pub fn function_with_bytes<const BYTES: &'static [u8]>() -> &'static [u8] { } // Also check the codepaths for custom DST -#[derive(std::marker::UnsizedConstParamTy, PartialEq, Eq)] +#[derive(std::marker::ConstParamTy, PartialEq, Eq)] struct MyStr(str); fn function_with_my_str<const S: &'static MyStr>() -> &'static MyStr { diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr b/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr index 7a936ced030..c2351c707d7 100644 --- a/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr +++ b/tests/ui/const-generics/transmute-const-param-static-reference.adt_const_params.stderr @@ -1,9 +1,13 @@ -error[E0741]: `&'static ()` can't be used as a const parameter type - --> $DIR/transmute-const-param-static-reference.rs:9:23 +error[E0658]: use of unstable library feature `unsized_const_params` + --> $DIR/transmute-const-param-static-reference.rs:9:14 | LL | struct Const<const P: &'static ()>; - | ^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(unsized_const_params)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date + = note: required for `&'static ()` to implement `ConstParamTy_` error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0741`. +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/const-generics/transmute-const-param-static-reference.rs b/tests/ui/const-generics/transmute-const-param-static-reference.rs index 0b47fd31eaf..bf164bdadb0 100644 --- a/tests/ui/const-generics/transmute-const-param-static-reference.rs +++ b/tests/ui/const-generics/transmute-const-param-static-reference.rs @@ -8,7 +8,7 @@ struct Const<const P: &'static ()>; //[min]~^ ERROR `&'static ()` is forbidden as the type of a const generic parameter -//[adt_const_params]~^^ ERROR `&'static ()` can't be used as a const parameter type +//[adt_const_params]~^^ ERROR use of unstable library feature `unsized_const_params` fn main() { const A: &'static () = unsafe { std::mem::transmute(10 as *const ()) }; diff --git a/tests/ui/const-generics/unsized_const_params/symbol_mangling_v0_str.rs b/tests/ui/const-generics/unsized_const_params/symbol_mangling_v0_str.rs index 359126f1251..429c401af1f 100644 --- a/tests/ui/const-generics/unsized_const_params/symbol_mangling_v0_str.rs +++ b/tests/ui/const-generics/unsized_const_params/symbol_mangling_v0_str.rs @@ -1,13 +1,13 @@ //@ check-pass //@ compile-flags: -Csymbol-mangling-version=v0 #![allow(incomplete_features)] -#![feature(unsized_const_params)] +#![feature(adt_const_params, unsized_const_params)] // Regression test for #116303 #[derive(PartialEq, Eq)] struct MyStr(str); -impl std::marker::UnsizedConstParamTy for MyStr {} +impl std::marker::ConstParamTy_ for MyStr {} fn function_with_my_str<const S: &'static MyStr>() -> &'static MyStr { S diff --git a/tests/ui/consts/const_refs_to_static_fail.stderr b/tests/ui/consts/const_refs_to_static_fail.stderr index c567b3e0ce1..2bb6d2b8fef 100644 --- a/tests/ui/consts/const_refs_to_static_fail.stderr +++ b/tests/ui/consts/const_refs_to_static_fail.stderr @@ -16,7 +16,7 @@ error: constant BAD_PATTERN cannot be used as pattern LL | BAD_PATTERN => {}, | ^^^^^^^^^^^ | - = note: constants that reference mutable or external memory cannot be used as pattern + = note: constants that reference mutable or external memory cannot be used as patterns error: aborting due to 3 previous errors diff --git a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr index f9088c318a6..226a9de285d 100644 --- a/tests/ui/consts/const_refs_to_static_fail_invalid.stderr +++ b/tests/ui/consts/const_refs_to_static_fail_invalid.stderr @@ -15,7 +15,7 @@ error: constant extern_::C cannot be used as pattern LL | C => {} | ^ | - = note: constants that reference mutable or external memory cannot be used as pattern + = note: constants that reference mutable or external memory cannot be used as patterns error: constant mutable::C cannot be used as pattern --> $DIR/const_refs_to_static_fail_invalid.rs:42:9 @@ -23,7 +23,7 @@ error: constant mutable::C cannot be used as pattern LL | C => {} | ^ | - = note: constants that reference mutable or external memory cannot be used as pattern + = note: constants that reference mutable or external memory cannot be used as patterns error: aborting due to 3 previous errors diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr index 6b70a211a72..5b8797c5116 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.stderr @@ -22,7 +22,7 @@ error: constant REF_INTERIOR_MUT cannot be used as pattern LL | REF_INTERIOR_MUT => {}, | ^^^^^^^^^^^^^^^^ | - = note: constants that reference mutable or external memory cannot be used as pattern + = note: constants that reference mutable or external memory cannot be used as patterns warning: skipping const checks | diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr index d753506cc94..c2b730375f2 100644 --- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr +++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.stderr @@ -10,7 +10,7 @@ error: constant SLICE_MUT cannot be used as pattern LL | SLICE_MUT => true, | ^^^^^^^^^ | - = note: constants that reference mutable or external memory cannot be used as pattern + = note: constants that reference mutable or external memory cannot be used as patterns error: constant U8_MUT cannot be used as pattern --> $DIR/const_refers_to_static_cross_crate.rs:44:9 @@ -18,7 +18,7 @@ error: constant U8_MUT cannot be used as pattern LL | U8_MUT => true, | ^^^^^^ | - = note: constants that reference mutable or external memory cannot be used as pattern + = note: constants that reference mutable or external memory cannot be used as patterns error: constant U8_MUT2 cannot be used as pattern --> $DIR/const_refers_to_static_cross_crate.rs:53:9 @@ -26,7 +26,7 @@ error: constant U8_MUT2 cannot be used as pattern LL | U8_MUT2 => true, | ^^^^^^^ | - = note: constants that reference mutable or external memory cannot be used as pattern + = note: constants that reference mutable or external memory cannot be used as patterns error: aborting due to 4 previous errors diff --git a/tests/ui/darwin-objc/darwin-objc-bad-arg.rs b/tests/ui/darwin-objc/darwin-objc-bad-arg.rs new file mode 100644 index 00000000000..70eb83aa052 --- /dev/null +++ b/tests/ui/darwin-objc/darwin-objc-bad-arg.rs @@ -0,0 +1,36 @@ +// Test that `objc::class!` and `objc::selector!` only take string literals. + +//@ edition: 2024 +//@ only-apple + +#![feature(darwin_objc)] + +use std::os::darwin::objc; + +pub fn main() { + let s = "NSObject"; + objc::class!(s); + //~^ ERROR attribute value must be a literal + + objc::class!(NSObject); + //~^ ERROR attribute value must be a literal + + objc::class!(123); + //~^ ERROR `objc::class!` expected a string literal + + objc::class!("NSObject\0"); + //~^ ERROR `objc::class!` may not contain null characters + + let s = "alloc"; + objc::selector!(s); + //~^ ERROR attribute value must be a literal + + objc::selector!(alloc); + //~^ ERROR attribute value must be a literal + + objc::selector!(123); + //~^ ERROR `objc::selector!` expected a string literal + + objc::selector!("alloc\0"); + //~^ ERROR `objc::selector!` may not contain null characters +} diff --git a/tests/ui/darwin-objc/darwin-objc-bad-arg.stderr b/tests/ui/darwin-objc/darwin-objc-bad-arg.stderr new file mode 100644 index 00000000000..99eeb27e30c --- /dev/null +++ b/tests/ui/darwin-objc/darwin-objc-bad-arg.stderr @@ -0,0 +1,50 @@ +error: attribute value must be a literal + --> $DIR/darwin-objc-bad-arg.rs:12:18 + | +LL | objc::class!(s); + | ^ + +error: attribute value must be a literal + --> $DIR/darwin-objc-bad-arg.rs:15:18 + | +LL | objc::class!(NSObject); + | ^^^^^^^^ + +error: `objc::class!` expected a string literal + --> $DIR/darwin-objc-bad-arg.rs:18:18 + | +LL | objc::class!(123); + | ^^^ + +error: `objc::class!` may not contain null characters + --> $DIR/darwin-objc-bad-arg.rs:21:18 + | +LL | objc::class!("NSObject\0"); + | ^^^^^^^^^^^^ + +error: attribute value must be a literal + --> $DIR/darwin-objc-bad-arg.rs:25:21 + | +LL | objc::selector!(s); + | ^ + +error: attribute value must be a literal + --> $DIR/darwin-objc-bad-arg.rs:28:21 + | +LL | objc::selector!(alloc); + | ^^^^^ + +error: `objc::selector!` expected a string literal + --> $DIR/darwin-objc-bad-arg.rs:31:21 + | +LL | objc::selector!(123); + | ^^^ + +error: `objc::selector!` may not contain null characters + --> $DIR/darwin-objc-bad-arg.rs:34:21 + | +LL | objc::selector!("alloc\0"); + | ^^^^^^^^^ + +error: aborting due to 8 previous errors + diff --git a/tests/ui/darwin-objc/darwin-objc-bad-const.rs b/tests/ui/darwin-objc/darwin-objc-bad-const.rs new file mode 100644 index 00000000000..ccf28697b48 --- /dev/null +++ b/tests/ui/darwin-objc/darwin-objc-bad-const.rs @@ -0,0 +1,17 @@ +// Test that `objc::class!` and `objc::selector!` aren't `const` expressions. +// The system gives them their final values at dynamic load time. + +//@ edition: 2024 +//@ only-apple + +#![feature(darwin_objc)] + +use std::os::darwin::objc; + +pub const CLASS: objc::Class = objc::class!("NSObject"); +//~^ ERROR cannot access extern static `CLASS::VAL` [E0080] + +pub const SELECTOR: objc::SEL = objc::selector!("alloc"); +//~^ ERROR cannot access extern static `SELECTOR::VAL` [E0080] + +pub fn main() {} diff --git a/tests/ui/darwin-objc/darwin-objc-bad-const.stderr b/tests/ui/darwin-objc/darwin-objc-bad-const.stderr new file mode 100644 index 00000000000..43d0b7d761f --- /dev/null +++ b/tests/ui/darwin-objc/darwin-objc-bad-const.stderr @@ -0,0 +1,19 @@ +error[E0080]: cannot access extern static `CLASS::VAL` + --> $DIR/darwin-objc-bad-const.rs:11:32 + | +LL | pub const CLASS: objc::Class = objc::class!("NSObject"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `CLASS` failed here + | + = note: this error originates in the macro `objc::class` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: cannot access extern static `SELECTOR::VAL` + --> $DIR/darwin-objc-bad-const.rs:14:33 + | +LL | pub const SELECTOR: objc::SEL = objc::selector!("alloc"); + | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `SELECTOR` failed here + | + = note: this error originates in the macro `objc::selector` (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 E0080`. diff --git a/tests/ui/darwin-objc/darwin-objc-bad-ref.rs b/tests/ui/darwin-objc/darwin-objc-bad-ref.rs new file mode 100644 index 00000000000..fb1437366dd --- /dev/null +++ b/tests/ui/darwin-objc/darwin-objc-bad-ref.rs @@ -0,0 +1,31 @@ +// Test that `objc::class!` and `objc::selector!` can't be returned by reference. +// A single instance may have multiple addresses (e.g. across dylib boundaries). + +//@ edition: 2024 +//@ only-apple + +#![feature(darwin_objc)] + +use std::os::darwin::objc; + +pub fn class_ref<'a>() -> &'a objc::Class { + &objc::class!("NSObject") + //~^ ERROR cannot return reference to temporary value [E0515] +} + +pub fn class_ref_static() -> &'static objc::Class { + &objc::class!("NSObject") + //~^ ERROR cannot return reference to temporary value [E0515] +} + +pub fn selector_ref<'a>() -> &'a objc::SEL { + &objc::selector!("alloc") + //~^ ERROR cannot return reference to temporary value [E0515] +} + +pub fn selector_ref_static() -> &'static objc::SEL { + &objc::selector!("alloc") + //~^ ERROR cannot return reference to temporary value [E0515] +} + +pub fn main() {} diff --git a/tests/ui/darwin-objc/darwin-objc-bad-ref.stderr b/tests/ui/darwin-objc/darwin-objc-bad-ref.stderr new file mode 100644 index 00000000000..b09e6a75c84 --- /dev/null +++ b/tests/ui/darwin-objc/darwin-objc-bad-ref.stderr @@ -0,0 +1,39 @@ +error[E0515]: cannot return reference to temporary value + --> $DIR/darwin-objc-bad-ref.rs:12:5 + | +LL | &objc::class!("NSObject") + | ^------------------------ + | || + | |temporary value created here + | returns a reference to data owned by the current function + +error[E0515]: cannot return reference to temporary value + --> $DIR/darwin-objc-bad-ref.rs:17:5 + | +LL | &objc::class!("NSObject") + | ^------------------------ + | || + | |temporary value created here + | returns a reference to data owned by the current function + +error[E0515]: cannot return reference to temporary value + --> $DIR/darwin-objc-bad-ref.rs:22:5 + | +LL | &objc::selector!("alloc") + | ^------------------------ + | || + | |temporary value created here + | returns a reference to data owned by the current function + +error[E0515]: cannot return reference to temporary value + --> $DIR/darwin-objc-bad-ref.rs:27:5 + | +LL | &objc::selector!("alloc") + | ^------------------------ + | || + | |temporary value created here + | returns a reference to data owned by the current function + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0515`. diff --git a/tests/ui/darwin-objc/darwin-objc-class-selector.rs b/tests/ui/darwin-objc/darwin-objc-class-selector.rs new file mode 100644 index 00000000000..b9a2fc3634f --- /dev/null +++ b/tests/ui/darwin-objc/darwin-objc-class-selector.rs @@ -0,0 +1,31 @@ +// Call `[NSObject class]` using `objc::class!` and `objc::selector!`. + +//@ edition: 2024 +//@ only-apple +//@ run-pass + +#![feature(darwin_objc)] + +use std::mem::transmute; +use std::os::darwin::objc; + +#[link(name = "Foundation", kind = "framework")] +unsafe extern "C" {} + +#[link(name = "objc", kind = "dylib")] +unsafe extern "C" { + unsafe fn objc_msgSend(); +} + +fn main() { + let msg_send_fn = unsafe { + transmute::< + unsafe extern "C" fn(), + unsafe extern "C" fn(objc::Class, objc::SEL) -> objc::Class, + >(objc_msgSend) + }; + let static_sel = objc::selector!("class"); + let static_class = objc::class!("NSObject"); + let runtime_class = unsafe { msg_send_fn(static_class, static_sel) }; + assert_eq!(static_class, runtime_class); +} diff --git a/tests/ui/darwin-objc/darwin-objc-class.rs b/tests/ui/darwin-objc/darwin-objc-class.rs new file mode 100644 index 00000000000..851149d8726 --- /dev/null +++ b/tests/ui/darwin-objc/darwin-objc-class.rs @@ -0,0 +1,39 @@ +// Test that `objc::class!` returns the same thing as `objc_lookUpClass`. + +//@ edition: 2024 +//@ only-apple +//@ run-pass + +#![feature(darwin_objc)] + +use std::ffi::c_char; +use std::os::darwin::objc; + +#[link(name = "Foundation", kind = "framework")] +unsafe extern "C" {} + +#[link(name = "objc")] +unsafe extern "C" { + fn objc_lookUpClass(methname: *const c_char) -> objc::Class; +} + +fn get_object_class() -> objc::Class { + objc::class!("NSObject") +} + +fn lookup_object_class() -> objc::Class { + unsafe { objc_lookUpClass(c"NSObject".as_ptr()) } +} + +fn get_string_class() -> objc::Class { + objc::class!("NSString") +} + +fn lookup_string_class() -> objc::Class { + unsafe { objc_lookUpClass(c"NSString".as_ptr()) } +} + +fn main() { + assert_eq!(get_object_class(), lookup_object_class()); + assert_eq!(get_string_class(), lookup_string_class()); +} diff --git a/tests/ui/darwin-objc/darwin-objc-selector.rs b/tests/ui/darwin-objc/darwin-objc-selector.rs new file mode 100644 index 00000000000..008ae4c4ca4 --- /dev/null +++ b/tests/ui/darwin-objc/darwin-objc-selector.rs @@ -0,0 +1,36 @@ +// Test that `objc::selector!` returns the same thing as `sel_registerName`. + +//@ edition: 2024 +//@ only-apple +//@ run-pass + +#![feature(darwin_objc)] + +use std::ffi::c_char; +use std::os::darwin::objc; + +#[link(name = "objc")] +unsafe extern "C" { + fn sel_registerName(methname: *const c_char) -> objc::SEL; +} + +fn get_alloc_selector() -> objc::SEL { + objc::selector!("alloc") +} + +fn register_alloc_selector() -> objc::SEL { + unsafe { sel_registerName(c"alloc".as_ptr()) } +} + +fn get_init_selector() -> objc::SEL { + objc::selector!("initWithCString:encoding:") +} + +fn register_init_selector() -> objc::SEL { + unsafe { sel_registerName(c"initWithCString:encoding:".as_ptr()) } +} + +fn main() { + assert_eq!(get_alloc_selector(), register_alloc_selector()); + assert_eq!(get_init_selector(), register_init_selector()); +} diff --git a/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs b/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs index 198f8d1bc10..6d12ab1e4cf 100644 --- a/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs +++ b/tests/ui/dist/cranelift-x86_64-unknown-linux-gnu-dist.rs @@ -2,6 +2,7 @@ // dist artifacts. //@ only-dist +//@ only-nightly (cranelift is not stable yet) //@ only-x86_64-unknown-linux-gnu //@ compile-flags: -Z codegen-backend=cranelift //@ run-pass diff --git a/tests/ui/drop/super-let-tail-expr-drop-order.rs b/tests/ui/drop/super-let-tail-expr-drop-order.rs new file mode 100644 index 00000000000..5b2ecfbb320 --- /dev/null +++ b/tests/ui/drop/super-let-tail-expr-drop-order.rs @@ -0,0 +1,192 @@ +//! Test for #145784: the argument to `pin!` should be treated as an extending expression if and +//! only if the whole `pin!` invocation is an extending expression. Likewise, since `pin!` is +//! implemented in terms of `super let`, test the same for `super let` initializers. Since the +//! argument to `pin!` and the initializer of `super let` are not temporary drop scopes, this only +//! affects lifetimes in two cases: +//! +//! - Block tail expressions in Rust 2024, which are both extending expressions and temporary drop +//! scopes; treating them as extending expressions within a non-extending `pin!` resulted in borrow +//! expression operands living past the end of the block. +//! +//! - Nested `super let` statements, which can have their binding and temporary lifetimes extended +//! when the block they're in is an extending expression. +//! +//! For more information on extending expressions, see +//! https://doc.rust-lang.org/reference/destructors.html#extending-based-on-expressions +//! +//! For tests that `super let` initializers aren't temporary drop scopes, and tests for +//! lifetime-extended `super let`, see tests/ui/borrowck/super-let-lifetime-and-drop.rs +//@ run-pass +//@ revisions: e2021 e2024 +//@ [e2021] edition: 2021 +//@ [e2024] edition: 2024 + +#![feature(super_let)] +#![allow(unused_braces)] + +use std::cell::RefCell; +use std::pin::pin; + +fn f<T>(_: LogDrop<'_>, x: T) -> T { x } + +fn main() { + // Test block arguments to `pin!` in non-extending expressions. + // In Rust 2021, block tail expressions aren't temporary drop scopes, so their temporaries + // should outlive the `pin!` invocation. + // In Rust 2024, block tail expressions are temporary drop scopes, so their temporaries should + // be dropped after evaluating the tail expression within the `pin!` invocation. + // By nesting two `pin!` calls, this ensures non-extended `pin!` doesn't extend an inner `pin!`. + assert_drop_order(1..=3, |o| { + #[cfg(e2021)] + ( + pin!(( + pin!({ &o.log(3) as *const LogDrop<'_> }), + drop(o.log(1)), + )), + drop(o.log(2)), + ); + #[cfg(e2024)] + ( + pin!(( + pin!({ &o.log(1) as *const LogDrop<'_> }), + drop(o.log(2)), + )), + drop(o.log(3)), + ); + }); + + // The same holds for `super let` initializers in non-extending expressions. + assert_drop_order(1..=4, |o| { + #[cfg(e2021)] + ( + { + super let _ = { + super let _ = { &o.log(4) as *const LogDrop<'_> }; + drop(o.log(1)) + }; + drop(o.log(2)) + }, + drop(o.log(3)), + ); + #[cfg(e2024)] + ( + { + super let _ = { + super let _ = { &o.log(1) as *const LogDrop<'_> }; + drop(o.log(2)) + }; + drop(o.log(3)) + }, + drop(o.log(4)), + ); + }); + + // Within an extending expression, the argument to `pin!` is also an extending expression, + // allowing borrow operands in block tail expressions to have extended lifetimes. + assert_drop_order(1..=2, |o| { + let _ = pin!({ &o.log(2) as *const LogDrop<'_> }); + drop(o.log(1)); + }); + + // The same holds for `super let` initializers in extending expressions. + assert_drop_order(1..=2, |o| { + let _ = { super let _ = { &o.log(2) as *const LogDrop<'_> }; }; + drop(o.log(1)); + }); + + // We have extending borrow expressions within an extending block + // expression (within an extending borrow expression) within a + // non-extending expresion within the initializer expression. + #[cfg(e2021)] + { + // These two should be the same. + assert_drop_order(1..=3, |e| { + let _v = f(e.log(1), &{ &raw const *&e.log(2) }); + drop(e.log(3)); + }); + assert_drop_order(1..=3, |e| { + let _v = f(e.log(1), { + super let v = &{ &raw const *&e.log(2) }; + v + }); + drop(e.log(3)); + }); + } + #[cfg(e2024)] + { + // These two should be the same. + assert_drop_order(1..=3, |e| { + let _v = f(e.log(2), &{ &raw const *&e.log(1) }); + drop(e.log(3)); + }); + assert_drop_order(1..=3, |e| { + let _v = f(e.log(2), { + super let v = &{ &raw const *&e.log(1) }; + v + }); + drop(e.log(3)); + }); + } + + // We have extending borrow expressions within a non-extending + // expression within the initializer expression. + // + // These two should be the same. + assert_drop_order(1..=3, |e| { + let _v = f(e.log(1), &&raw const *&e.log(2)); + drop(e.log(3)); + }); + assert_drop_order(1..=3, |e| { + let _v = f(e.log(1), { + super let v = &&raw const *&e.log(2); + v + }); + drop(e.log(3)); + }); + + // We have extending borrow expressions within an extending block + // expression (within an extending borrow expression) within the + // initializer expression. + // + // These two should be the same. + assert_drop_order(1..=2, |e| { + let _v = &{ &raw const *&e.log(2) }; + drop(e.log(1)); + }); + assert_drop_order(1..=2, |e| { + let _v = { + super let v = &{ &raw const *&e.log(2) }; + v + }; + drop(e.log(1)); + }); +} + +// # Test scaffolding... + +struct DropOrder(RefCell<Vec<u64>>); +struct LogDrop<'o>(&'o DropOrder, u64); + +impl DropOrder { + fn log(&self, n: u64) -> LogDrop<'_> { + LogDrop(self, n) + } +} + +impl<'o> Drop for LogDrop<'o> { + fn drop(&mut self) { + self.0.0.borrow_mut().push(self.1); + } +} + +#[track_caller] +fn assert_drop_order( + ex: impl IntoIterator<Item = u64>, + f: impl Fn(&DropOrder), +) { + let order = DropOrder(RefCell::new(Vec::new())); + f(&order); + let order = order.0.into_inner(); + let expected: Vec<u64> = ex.into_iter().collect(); + assert_eq!(order, expected); +} diff --git a/tests/ui/feature-gates/feature-gate-adt_const_params.rs b/tests/ui/feature-gates/feature-gate-adt_const_params.rs index 8a3bcf25963..7efa529c557 100644 --- a/tests/ui/feature-gates/feature-gate-adt_const_params.rs +++ b/tests/ui/feature-gates/feature-gate-adt_const_params.rs @@ -1,2 +1,6 @@ -struct Foo<const NAME: &'static str>; //~ ERROR `&'static str` is forbidden +struct Bar(u8); + +struct Foo<const N: Bar>; +//~^ ERROR: `Bar` is forbidden as the type of a const generic parameter + fn main() {} diff --git a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr index 18d514f8cb5..7ea91a8f4c2 100644 --- a/tests/ui/feature-gates/feature-gate-adt_const_params.stderr +++ b/tests/ui/feature-gates/feature-gate-adt_const_params.stderr @@ -1,18 +1,14 @@ -error: `&'static str` is forbidden as the type of a const generic parameter - --> $DIR/feature-gate-adt_const_params.rs:1:24 +error: `Bar` is forbidden as the type of a const generic parameter + --> $DIR/feature-gate-adt_const_params.rs:3:21 | -LL | struct Foo<const NAME: &'static str>; - | ^^^^^^^^^^^^ +LL | struct Foo<const N: Bar>; + | ^^^ | = note: the only supported types are integers, `bool`, and `char` help: add `#![feature(adt_const_params)]` to the crate attributes to enable more complex and user defined types | LL + #![feature(adt_const_params)] | -help: add `#![feature(unsized_const_params)]` to the crate attributes to enable references to implement the `ConstParamTy` trait - | -LL + #![feature(unsized_const_params)] - | error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-18088.rs b/tests/ui/issues/issue-18088.rs deleted file mode 100644 index ba198884c63..00000000000 --- a/tests/ui/issues/issue-18088.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@ check-pass - -pub trait Indexable<T>: std::ops::Index<usize, Output = T> { - fn index2(&self, i: usize) -> &T { - &self[i] - } -} -fn main() {} diff --git a/tests/ui/issues/issue-21950.rs b/tests/ui/issues/issue-21950.rs deleted file mode 100644 index 7a85ac91bca..00000000000 --- a/tests/ui/issues/issue-21950.rs +++ /dev/null @@ -1,12 +0,0 @@ -trait Add<Rhs=Self> { - type Output; -} - -impl Add for i32 { - type Output = i32; -} - -fn main() { - let x = &10 as &dyn Add; - //~^ ERROR E0191 -} diff --git a/tests/ui/issues/issue-2284.rs b/tests/ui/issues/issue-2284.rs deleted file mode 100644 index 358331ecd9a..00000000000 --- a/tests/ui/issues/issue-2284.rs +++ /dev/null @@ -1,13 +0,0 @@ -//@ run-pass -#![allow(dead_code)] - -trait Send { - fn f(&self); -} - -fn f<T:Send>(t: T) { - t.f(); -} - -pub fn main() { -} diff --git a/tests/ui/layout/thaw-transmute-invalid-enum.rs b/tests/ui/layout/thaw-transmute-invalid-enum.rs index a7c2e1a86de..20fc8d46359 100644 --- a/tests/ui/layout/thaw-transmute-invalid-enum.rs +++ b/tests/ui/layout/thaw-transmute-invalid-enum.rs @@ -9,6 +9,7 @@ mod assert { where Dst: TransmuteFrom<Src>, //~^ ERROR: use of unstable library feature `transmutability` + //~^^ ERROR: use of unstable library feature `transmutability` { } } diff --git a/tests/ui/layout/thaw-transmute-invalid-enum.stderr b/tests/ui/layout/thaw-transmute-invalid-enum.stderr index d12fc4694e0..2b89159c263 100644 --- a/tests/ui/layout/thaw-transmute-invalid-enum.stderr +++ b/tests/ui/layout/thaw-transmute-invalid-enum.stderr @@ -1,5 +1,5 @@ error[E0412]: cannot find type `Subset` in this scope - --> $DIR/thaw-transmute-invalid-enum.rs:34:41 + --> $DIR/thaw-transmute-invalid-enum.rs:35:41 | LL | assert::is_transmutable::<Superset, Subset>(); | ^^^^^^ not found in this scope @@ -10,7 +10,7 @@ LL | fn test<Subset>() { | ++++++++ error[E0517]: attribute should be applied to a struct or union - --> $DIR/thaw-transmute-invalid-enum.rs:21:11 + --> $DIR/thaw-transmute-invalid-enum.rs:22:11 | LL | #[repr(C, packed(2))] | ^^^^^^^^^ @@ -50,8 +50,19 @@ LL | Dst: TransmuteFrom<Src>, = help: add `#![feature(transmutability)]` to the crate attributes to enable = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +error[E0658]: use of unstable library feature `transmutability` + --> $DIR/thaw-transmute-invalid-enum.rs:10:14 + | +LL | Dst: TransmuteFrom<Src>, + | ^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(transmutability)]` to the crate attributes to enable + = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date +note: required by a bound in `TransmuteFrom` + --> $SRC_DIR/core/src/mem/transmutability.rs:LL:COL + error[E0740]: field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union - --> $DIR/thaw-transmute-invalid-enum.rs:29:9 + --> $DIR/thaw-transmute-invalid-enum.rs:30:9 | LL | a: Ox00, | ^^^^^^^ @@ -62,7 +73,7 @@ help: wrap the field type in `ManuallyDrop<...>` LL | a: std::mem::ManuallyDrop<Ox00>, | +++++++++++++++++++++++ + -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors Some errors have detailed explanations: E0412, E0517, E0658, E0740. For more information about an error, try `rustc --explain E0412`. diff --git a/tests/ui/lifetimes/issue-105507.fixed b/tests/ui/lifetimes/issue-105507.fixed index 46d4f14a245..a3c4e5784b8 100644 --- a/tests/ui/lifetimes/issue-105507.fixed +++ b/tests/ui/lifetimes/issue-105507.fixed @@ -31,7 +31,7 @@ impl<T> ProjectedMyTrait for T fn require_trait<T: MyTrait>(_: T) {} -fn foo<T : MyTrait + 'static + 'static, U : MyTrait + 'static + 'static>(wrap: Wrapper<'_, Option<T>>, wrap1: Wrapper<'_, Option<U>>) { +fn foo<T : MyTrait + 'static, U : MyTrait + 'static>(wrap: Wrapper<'_, Option<T>>, wrap1: Wrapper<'_, Option<U>>) { //~^ HELP consider restricting the type parameter to the `'static` lifetime //~| HELP consider restricting the type parameter to the `'static` lifetime require_trait(wrap); diff --git a/tests/ui/lint/unused_parens_follow_ident.fixed b/tests/ui/lint/unused_parens_follow_ident.fixed new file mode 100644 index 00000000000..e61b287e5a6 --- /dev/null +++ b/tests/ui/lint/unused_parens_follow_ident.fixed @@ -0,0 +1,17 @@ +//@ run-rustfix + +#![deny(unused_parens)] + +macro_rules! wrap { + ($name:ident $arg:expr) => { + $name($arg); + }; +} + +fn main() { + wrap!(unary routine()); //~ ERROR unnecessary parentheses around function argument + wrap!(unary routine()); //~ ERROR unnecessary parentheses around function argument +} + +fn unary(_: ()) {} +fn routine() {} diff --git a/tests/ui/lint/unused_parens_follow_ident.rs b/tests/ui/lint/unused_parens_follow_ident.rs new file mode 100644 index 00000000000..32a163345b2 --- /dev/null +++ b/tests/ui/lint/unused_parens_follow_ident.rs @@ -0,0 +1,17 @@ +//@ run-rustfix + +#![deny(unused_parens)] + +macro_rules! wrap { + ($name:ident $arg:expr) => { + $name($arg); + }; +} + +fn main() { + wrap!(unary(routine())); //~ ERROR unnecessary parentheses around function argument + wrap!(unary (routine())); //~ ERROR unnecessary parentheses around function argument +} + +fn unary(_: ()) {} +fn routine() {} diff --git a/tests/ui/lint/unused_parens_follow_ident.stderr b/tests/ui/lint/unused_parens_follow_ident.stderr new file mode 100644 index 00000000000..ce7bb26778c --- /dev/null +++ b/tests/ui/lint/unused_parens_follow_ident.stderr @@ -0,0 +1,31 @@ +error: unnecessary parentheses around function argument + --> $DIR/unused_parens_follow_ident.rs:12:16 + | +LL | wrap!(unary(routine())); + | ^ ^ + | +note: the lint level is defined here + --> $DIR/unused_parens_follow_ident.rs:3:9 + | +LL | #![deny(unused_parens)] + | ^^^^^^^^^^^^^ +help: remove these parentheses + | +LL - wrap!(unary(routine())); +LL + wrap!(unary routine()); + | + +error: unnecessary parentheses around function argument + --> $DIR/unused_parens_follow_ident.rs:13:17 + | +LL | wrap!(unary (routine())); + | ^ ^ + | +help: remove these parentheses + | +LL - wrap!(unary (routine())); +LL + wrap!(unary routine()); + | + +error: aborting due to 2 previous errors + diff --git a/tests/ui/parser/expr-as-stmt.fixed b/tests/ui/parser/expr-as-stmt.fixed index bfae55047ed..b3a491200ed 100644 --- a/tests/ui/parser/expr-as-stmt.fixed +++ b/tests/ui/parser/expr-as-stmt.fixed @@ -66,7 +66,7 @@ fn asteroids() -> impl FnOnce() -> bool { // https://github.com/rust-lang/rust/issues/105179 fn r#match() -> i32 { - ((match () { () => 1 })) + match () { () => 1 } //~ ERROR expected expression, found `+` + (match () { () => 1 }) + match () { () => 1 } //~ ERROR expected expression, found `+` //~^ ERROR mismatched types } @@ -82,7 +82,7 @@ fn matches() -> bool { (match () { _ => true }) && match () { _ => true }; //~ ERROR mismatched types //~^ ERROR expected `;`, found keyword `match` (match () { _ => true }) && true; //~ ERROR mismatched types - ((match () { _ => true })) && true //~ ERROR mismatched types + (match () { _ => true }) && true //~ ERROR mismatched types //~^ ERROR mismatched types } fn main() {} diff --git a/tests/ui/rustc_public-ir-print/async-closure.rs b/tests/ui/rustc_public-ir-print/async-closure.rs index 80f96e09cfc..bd8c7e888a3 100644 --- a/tests/ui/rustc_public-ir-print/async-closure.rs +++ b/tests/ui/rustc_public-ir-print/async-closure.rs @@ -1,6 +1,6 @@ //@ compile-flags: -Z unpretty=stable-mir --crate-type lib -C panic=abort -Zmir-opt-level=0 //@ check-pass -//@ only-x86_64 +//@ only-64bit //@ edition: 2024 //@ needs-unwind unwind edges are different with panic=abort diff --git a/tests/ui/rustc_public-ir-print/async-closure.stdout b/tests/ui/rustc_public-ir-print/async-closure.stdout index 73e9b8fc097..5113dc5048b 100644 --- a/tests/ui/rustc_public-ir-print/async-closure.stdout +++ b/tests/ui/rustc_public-ir-print/async-closure.stdout @@ -40,30 +40,28 @@ fn foo::{closure#0}::{closure#0}(_1: Pin<&mut {async closure body@$DIR/async-clo let _3: i32; let mut _4: &i32; let mut _5: (); - let mut _6: &mut Context<'_>; - let mut _7: u32; + let mut _6: u32; + let mut _7: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; let mut _8: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; let mut _9: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; - let mut _10: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; - debug _task_context => _6; + debug _task_context => _2; debug y => (*((*(_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})).0: &i32)); debug y => _3; bb0: { - _8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); - _7 = discriminant((*_8)); - switchInt(move _7) -> [0: bb1, 1: bb2, otherwise: bb3]; + _7 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + _6 = discriminant((*_7)); + switchInt(move _6) -> [0: bb1, 1: bb2, otherwise: bb3]; } bb1: { - _6 = move _2; StorageLive(_3); - _9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); - _4 = CopyForDeref(((*_9).0: &i32)); + _8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + _4 = CopyForDeref(((*_8).0: &i32)); _3 = (*_4); _5 = (); StorageDead(_3); _0 = std::task::Poll::Ready(move _5); - _10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); - discriminant((*_10)) = 1; + _9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + discriminant((*_9)) = 1; return; } bb2: { @@ -78,30 +76,28 @@ fn foo::{closure#0}::{synthetic#0}(_1: Pin<&mut {async closure body@$DIR/async-c let _3: i32; let mut _4: &i32; let mut _5: (); - let mut _6: &mut Context<'_>; - let mut _7: u32; + let mut _6: u32; + let mut _7: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; let mut _8: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; let mut _9: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; - let mut _10: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6}; - debug _task_context => _6; + debug _task_context => _2; debug y => (*((*(_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})).0: &i32)); debug y => _3; bb0: { - _8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); - _7 = discriminant((*_8)); - switchInt(move _7) -> [0: bb1, 1: bb2, otherwise: bb3]; + _7 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + _6 = discriminant((*_7)); + switchInt(move _6) -> [0: bb1, 1: bb2, otherwise: bb3]; } bb1: { - _6 = move _2; StorageLive(_3); - _9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); - _4 = CopyForDeref(((*_9).0: &i32)); + _8 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + _4 = CopyForDeref(((*_8).0: &i32)); _3 = (*_4); _5 = (); StorageDead(_3); _0 = std::task::Poll::Ready(move _5); - _10 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); - discriminant((*_10)) = 1; + _9 = CopyForDeref((_1.0: &mut {async closure body@$DIR/async-closure.rs:9:22: 11:6})); + discriminant((*_9)) = 1; return; } bb2: { diff --git a/tests/ui/suggestions/apitit-unimplemented-method.rs b/tests/ui/suggestions/apitit-unimplemented-method.rs index b182e1939b3..c0cd709e230 100644 --- a/tests/ui/suggestions/apitit-unimplemented-method.rs +++ b/tests/ui/suggestions/apitit-unimplemented-method.rs @@ -4,9 +4,12 @@ extern crate dep; use dep::*; struct Local; + impl Trait for Local {} //~^ ERROR not all trait items implemented //~| HELP implement the missing item: `fn foo(_: impl Sized) { todo!() }` -//~| HELP implement the missing item: `fn bar<T>(_: impl Sized) { todo!() }` +//~| HELP implement the missing item: `fn bar<T>(_: impl Sized) where Foo<T>: MetaSized { todo!() }` +//~| HELP implement the missing item: `fn baz<const N: usize>() { todo!() }` +//~| HELP implement the missing item: `fn quux<'a: 'b, 'b, T>() where T: ?Sized { todo!() }` fn main() {} diff --git a/tests/ui/suggestions/apitit-unimplemented-method.stderr b/tests/ui/suggestions/apitit-unimplemented-method.stderr index b309a64e958..1f2e0ea2cad 100644 --- a/tests/ui/suggestions/apitit-unimplemented-method.stderr +++ b/tests/ui/suggestions/apitit-unimplemented-method.stderr @@ -1,11 +1,13 @@ -error[E0046]: not all trait items implemented, missing: `foo`, `bar` - --> $DIR/apitit-unimplemented-method.rs:7:1 +error[E0046]: not all trait items implemented, missing: `foo`, `bar`, `baz`, `quux` + --> $DIR/apitit-unimplemented-method.rs:8:1 | LL | impl Trait for Local {} - | ^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar` in implementation + | ^^^^^^^^^^^^^^^^^^^^ missing `foo`, `bar`, `baz`, `quux` in implementation | = help: implement the missing item: `fn foo(_: impl Sized) { todo!() }` - = help: implement the missing item: `fn bar<T>(_: impl Sized) { todo!() }` + = help: implement the missing item: `fn bar<T>(_: impl Sized) where Foo<T>: MetaSized { todo!() }` + = help: implement the missing item: `fn baz<const N: usize>() { todo!() }` + = help: implement the missing item: `fn quux<'a: 'b, 'b, T>() where T: ?Sized { todo!() }` error: aborting due to 1 previous error diff --git a/tests/ui/suggestions/auxiliary/dep.rs b/tests/ui/suggestions/auxiliary/dep.rs index ac0de418313..c28c8b8a52f 100644 --- a/tests/ui/suggestions/auxiliary/dep.rs +++ b/tests/ui/suggestions/auxiliary/dep.rs @@ -1,4 +1,16 @@ +#![feature(sized_hierarchy)] + +use std::marker::MetaSized; + +pub struct Foo<T> { + inner: T, +} + pub trait Trait { fn foo(_: impl Sized); - fn bar<T>(_: impl Sized); + fn bar<T>(_: impl Sized) + where + Foo<T>: MetaSized; + fn baz<'a, const N: usize>(); + fn quux<'a: 'b, 'b, T: ?Sized>(); } diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.fixed b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.fixed index 99433f73320..8a2be310e0d 100644 --- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.fixed +++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-2.fixed @@ -8,7 +8,7 @@ pub struct Vector2<T: Debug + Copy + Clone> { } #[derive(Debug, Copy, Clone)] -pub struct AABB<K: Debug + std::marker::Copy + std::marker::Copy + std::marker::Copy + std::marker::Copy> { +pub struct AABB<K: Debug + std::marker::Copy> { pub loc: Vector2<K>, //~ ERROR the trait bound `K: Copy` is not satisfied //~^ ERROR the trait bound `K: Copy` is not satisfied //~| ERROR the trait bound `K: Copy` is not satisfied diff --git a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.fixed b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.fixed index 6da3e351ffb..74df1d7c7cf 100644 --- a/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.fixed +++ b/tests/ui/suggestions/missing-bound-in-derive-copy-impl-3.fixed @@ -8,7 +8,7 @@ pub struct Vector2<T: Debug + Copy + Clone>{ } #[derive(Debug, Copy, Clone)] //~ ERROR the trait `Copy` cannot be implemented for this type -pub struct AABB<K: Copy + Debug + std::fmt::Debug + std::fmt::Debug + std::fmt::Debug>{ +pub struct AABB<K: Copy + Debug + std::fmt::Debug>{ pub loc: Vector2<K>, //~ ERROR `K` doesn't implement `Debug` //~^ ERROR `K` doesn't implement `Debug` pub size: Vector2<K> //~ ERROR `K` doesn't implement `Debug` diff --git a/tests/ui/suggestions/trait-impl-bound-suggestions.fixed b/tests/ui/suggestions/trait-impl-bound-suggestions.fixed index 9d3168f5acd..49793b4b6f4 100644 --- a/tests/ui/suggestions/trait-impl-bound-suggestions.fixed +++ b/tests/ui/suggestions/trait-impl-bound-suggestions.fixed @@ -10,7 +10,7 @@ struct ConstrainedStruct<X: Copy> { } #[allow(dead_code)] -trait InsufficientlyConstrainedGeneric<X=()> where Self: Sized, X: std::marker::Copy, X: std::marker::Copy { +trait InsufficientlyConstrainedGeneric<X=()> where Self: Sized, X: std::marker::Copy { fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> { //~^ ERROR the trait bound `X: Copy` is not satisfied ConstrainedStruct { x } @@ -20,7 +20,7 @@ trait InsufficientlyConstrainedGeneric<X=()> where Self: Sized, X: std::marker:: // Regression test for #120838 #[allow(dead_code)] -trait InsufficientlyConstrainedGenericWithEmptyWhere<X=()> where Self: Sized, X: std::marker::Copy, X: std::marker::Copy { +trait InsufficientlyConstrainedGenericWithEmptyWhere<X=()> where Self: Sized, X: std::marker::Copy { fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> { //~^ ERROR the trait bound `X: Copy` is not satisfied ConstrainedStruct { x } diff --git a/tests/ui/symbol-names/const-generics-structural-demangling.rs b/tests/ui/symbol-names/const-generics-structural-demangling.rs index 06e3ce51fa6..0b4af61f991 100644 --- a/tests/ui/symbol-names/const-generics-structural-demangling.rs +++ b/tests/ui/symbol-names/const-generics-structural-demangling.rs @@ -6,7 +6,7 @@ #![feature(adt_const_params, unsized_const_params, decl_macro, rustc_attrs)] #![allow(incomplete_features)] -use std::marker::UnsizedConstParamTy; +use std::marker::ConstParamTy; pub struct RefByte<const RB: &'static u8>; @@ -42,7 +42,7 @@ pub struct TupleByteBool<const TBB: (u8, bool)>; //~| ERROR demangling-alt(<c::TupleByteBool<{(1, false)}>>) impl TupleByteBool<{ (1, false) }> {} -#[derive(PartialEq, Eq, UnsizedConstParamTy)] +#[derive(PartialEq, Eq, ConstParamTy)] pub enum MyOption<T> { Some(T), None, @@ -66,7 +66,7 @@ impl OptionUsize<{ MyOption::None }> {} //~| ERROR demangling-alt(<c::OptionUsize<{c::MyOption::<usize>::Some(0)}>>) impl OptionUsize<{ MyOption::Some(0) }> {} -#[derive(PartialEq, Eq, UnsizedConstParamTy)] +#[derive(PartialEq, Eq, ConstParamTy)] pub struct Foo { s: &'static str, ch: char, @@ -83,7 +83,7 @@ impl Foo_<{ Foo { s: "abc", ch: 'x', slice: &[1, 2, 3] } }> {} // NOTE(eddyb) this tests specifically the use of disambiguators in field names, // using macros 2.0 hygiene to create a `struct` with conflicting field names. macro duplicate_field_name_test($x:ident) { - #[derive(PartialEq, Eq, UnsizedConstParamTy)] + #[derive(PartialEq, Eq, ConstParamTy)] pub struct Bar { $x: u8, x: u16, diff --git a/tests/ui/issues/issue-19479.rs b/tests/ui/traits/associated_type_bound/assoc-type-via-another-trait-issue-19479.rs index ed586b76550..f17a89bcb5f 100644 --- a/tests/ui/issues/issue-19479.rs +++ b/tests/ui/traits/associated_type_bound/assoc-type-via-another-trait-issue-19479.rs @@ -1,5 +1,11 @@ //@ check-pass +//! Tests that it's possible to define an associated type in a trait +//! using an associated type from type parameter bound trait in a blanket implementation. +//! +//! # Context +//! Original issue: https://github.com/rust-lang/rust/issues/19479 + trait Base { fn dummy(&self) { } } diff --git a/tests/ui/traits/cast-as-dyn-trait-wo-assoc-type-issue-21950.rs b/tests/ui/traits/cast-as-dyn-trait-wo-assoc-type-issue-21950.rs new file mode 100644 index 00000000000..3c381505450 --- /dev/null +++ b/tests/ui/traits/cast-as-dyn-trait-wo-assoc-type-issue-21950.rs @@ -0,0 +1,19 @@ +//! Tests that compiler yields error E0191 when value with existing trait implementation +//! is cast as same `dyn` trait without specifying associated type at the cast. +//! +//! # Context +//! Original issue: https://github.com/rust-lang/rust/issues/21950 + +trait Add<Rhs=Self> { + type Output; +} + +impl Add for i32 { + type Output = i32; +} + +fn main() { + let x = &10 as &dyn Add<i32, Output = i32>; //OK + let x = &10 as &dyn Add; + //~^ ERROR E0191 +} diff --git a/tests/ui/issues/issue-21950.stderr b/tests/ui/traits/cast-as-dyn-trait-wo-assoc-type-issue-21950.stderr index 24230cfe17f..5f4974e6f23 100644 --- a/tests/ui/issues/issue-21950.stderr +++ b/tests/ui/traits/cast-as-dyn-trait-wo-assoc-type-issue-21950.stderr @@ -1,5 +1,5 @@ error[E0191]: the value of the associated type `Output` in `Add` must be specified - --> $DIR/issue-21950.rs:10:25 + --> $DIR/cast-as-dyn-trait-wo-assoc-type-issue-21950.rs:17:25 | LL | type Output; | ----------- `Output` defined here diff --git a/tests/ui/traits/core-marker-name-shadowing-issue-2284.rs b/tests/ui/traits/core-marker-name-shadowing-issue-2284.rs new file mode 100644 index 00000000000..e5d083ac8c3 --- /dev/null +++ b/tests/ui/traits/core-marker-name-shadowing-issue-2284.rs @@ -0,0 +1,21 @@ +//@ run-pass +#![allow(dead_code)] + +//! Tests that user-defined trait is prioritized in compile time over +//! the core::marker trait with the same name, allowing shadowing core traits. +//! +//! # Context +//! Original issue: https://github.com/rust-lang/rust/issues/2284 +//! Original fix pull request: https://github.com/rust-lang/rust/pull/3792 + + +trait Send { + fn f(&self); +} + +fn f<T:Send>(t: T) { + t.f(); +} + +pub fn main() { +} diff --git a/tests/ui/traits/inheritance/supertrait-operator-issue-18088.rs b/tests/ui/traits/inheritance/supertrait-operator-issue-18088.rs new file mode 100644 index 00000000000..8bd45cd54a4 --- /dev/null +++ b/tests/ui/traits/inheritance/supertrait-operator-issue-18088.rs @@ -0,0 +1,13 @@ +//@ check-pass + +//! Tests that operators from supertrait are available directly on `self` for an inheritor trait. +//! +//! # Context +//! Original issue: https://github.com/rust-lang/rust/issues/18088 + +pub trait Indexable<T>: std::ops::Index<usize, Output = T> { + fn index2(&self, i: usize) -> &T { + &self[i] + } +} +fn main() {} diff --git a/tests/ui/type-inference/has_sigdrop.rs b/tests/ui/type-inference/has_sigdrop.rs new file mode 100644 index 00000000000..c3d835cfe16 --- /dev/null +++ b/tests/ui/type-inference/has_sigdrop.rs @@ -0,0 +1,18 @@ +//@ run-pass +// Inference, canonicalization, and significant drops should work nicely together. +// Related issue: #86868 + +#[clippy::has_significant_drop] +struct DropGuy {} + +fn creator() -> DropGuy { + DropGuy {} +} + +fn dropper() { + let _ = creator(); +} + +fn main() { + dropper(); +} |
